<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:base="https://httpster.io/atom.xml">
  <title>httpsterio&#39;s ramblings and articles</title>
  <subtitle>The random ramblings of a Finnish 30-something year old designer and creative.</subtitle>
  <link href="https://httpster.io/atom.xml" rel="self" />
  <link href="https://httpster.io/" />
  <updated>2025-04-15T00:00:00Z</updated>
  <id>https://httpster.io/atom.xml</id>
  <author>
    <name>Sami Mäkelä</name>
    <uri>https://httpster.io</uri>
  </author>  <entry>
    <title>Building Jypeli executables on Windows and Mac</title>
    <link href="https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/" />
    <updated>2025-04-15T00:00:00Z</updated>
    <id>https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;table-of-content&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#table-of-content&quot;&gt;Table of Content&lt;/a&gt;&lt;/h2&gt;
&lt;ol class=&quot;list&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#intro&quot;&gt;Intro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#building-for-windows&quot;&gt;Building for Windows&lt;/a&gt;&lt;br /&gt;
2.1. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#visual-studio&quot;&gt;Visual Studio&lt;/a&gt;&lt;br /&gt;
2.2. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#dotnet-build&quot;&gt;dotnet build&lt;/a&gt;&lt;br /&gt;
2.3. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#jetbrains-rider&quot;&gt;Jetbrains Rider&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#building-for-macos&quot;&gt;Building for MacOS&lt;/a&gt;&lt;br /&gt;
3.1. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#dotnet-publish&quot;&gt;dotnet publish&lt;/a&gt;&lt;br /&gt;
3.2. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#bundling-manually&quot;&gt;Bundling manually&lt;/a&gt;&lt;br /&gt;
3.3. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#bundling-script&quot;&gt;Bundling script&lt;/a&gt;&lt;br /&gt;
3.4. &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#removing-the-app-from-quarantine&quot;&gt;Removing the app from quarantine&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#final-thoughts&quot;&gt;Final thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;intro&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#intro&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/Jypeli-JYU/Jypeli&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Jypeli&lt;/a&gt; is the University of Jyväskylä’s fork of Microsoft’s XNA, released way back in 2010. It’s still used to teach the Programming 1 course at the university, which is why I ended up making a game with it in 2020.&lt;/p&gt;
&lt;p&gt;Having spent a few weeks going through all of the &lt;a href=&quot;https://httpster.io/projects&quot;&gt;game projects&lt;/a&gt; I’ve been a part of, I found myself updating my Jypeli game &lt;a href=&quot;https://github.com/httpsterio/CueBit&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;CueBit&lt;/a&gt; five years later.&lt;/p&gt;
&lt;p&gt;This post isn’t going to be a primer on how to get started with Jypeli, the &lt;a href=&quot;https://tim.jyu.fi/velp/kurssit/jypeli/wiki&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;official materials&lt;/a&gt; and Programming 1 course are better than anything I could write.&lt;/p&gt;
&lt;p&gt;Rather, I thought I’d show how I managed to build self-contained single file executables for Jypeli games on both Windows and MacOS. The official material doesn’t really touch on that and it’s more focused on getting the project set up and doing stuff with the engine itself.&lt;/p&gt;
&lt;h2 id=&quot;building-for-windows&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#building-for-windows&quot;&gt;Building for Windows&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Jypeli can be built with Visual Studio, .NET SDK with the &lt;em&gt;dotnet build&lt;/em&gt; console command. or with JetBrains Rider.&lt;/p&gt;
&lt;p&gt;I recommend Rider, but will walk through all of the options.&lt;/p&gt;
&lt;h3 id=&quot;visual-studio&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#visual-studio&quot;&gt;Visual Studio&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In order to use Jypeli with Visual Studio, you must already have the .NET 8.0 SDK installed, but in case you don’t have it, grab it from &lt;a href=&quot;https://dotnet.microsoft.com/en-us/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dotnet.microsoft.com/en-us/download&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you don’t mind a bazillion dll-files being included with your final project, doing a regular build in Visual Studio should produce a working exe in a folder of files. You should find it roughly in &lt;code&gt;bin/Release/net8.0/win-x64/&lt;/code&gt;. Just zip up the whole folder and that’s that.&lt;/p&gt;
&lt;p&gt;The user will need to install the .NET 8.0.15 runtime to be able to play the game.&lt;/p&gt;
&lt;p&gt;Visual Studio also has the possibility to &lt;em&gt;publish&lt;/em&gt; the game, but in my experience it breaks easily. You need to disable trimming by creating a property group in your &lt;code&gt;.csproj&lt;/code&gt; file like so&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;net8.0&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;RuntimeIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;win-x64&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;RuntimeIdentifier&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;PublishTrimmed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;false&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;PublishTrimmed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;SelfContained&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;true&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;SelfContained&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you go with this option, your game will end up in &lt;code&gt;bin/Release/net8.0/win-x64/publish/&lt;/code&gt;. The SelfContained directive includes the .NET runtime in the published file, which will likely double or triple the game size, but it’ll run more reliably without any extra installs required. You can also add&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;PublishSingleFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;true&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;PublishSingleFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the property group to create a single exe without all the adjacent files, but I didn’t manage to get it to work.&lt;/p&gt;
&lt;p&gt;If you have a .ico icon, you should also add it to the property group above like so:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ApplicationIcon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;path/to/icon.ico&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ApplicationIcon&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;dotnet-build&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#dotnet-build&quot;&gt;dotnet build&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you prefer the terminal or just want to script things, the dotnet CLI gets the job done. You’ll need the .NET 8 SDK installed, and your project should already be targeting .NET 8.0.&lt;/p&gt;
&lt;p&gt;To build a self-contained Windows version:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet publish &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; Release &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; win-x64 --self-contained &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; /p:PublishSingleFile&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true /p:PublishTrimmed&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;false&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What that does:&lt;/p&gt;
&lt;ul class=&quot;list&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-c Release&lt;/code&gt; builds in Release mode&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;-r win-x64&lt;/code&gt; targets Windows 64-bit&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;--self-contained true&lt;/code&gt; means the .NET runtime is bundled in&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PublishSingleFile=true&lt;/code&gt; tries to spit out one .exe&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;PublishTrimmed=false&lt;/code&gt; avoids breaking stuff by removing unused code &lt;em&gt;(which Jypeli really doesn’t like)&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You’ll find the result in &lt;code&gt;bin/Release/net8.0/win-x64/publish/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If everything works, you get a single .exe you can send around. In practice, it’s hit-or-miss—Jypeli’s native dependencies sometimes force extra files in. Still, the folder’s pretty tidy and runs out of the box.&lt;/p&gt;
&lt;p&gt;If &lt;code&gt;PublishSingleFile&lt;/code&gt; refuses to cooperate (which it might), just leave it out or set it to false and ship the full folder. Less elegant, but it works.&lt;/p&gt;
&lt;p&gt;Icons and other settings in your &lt;code&gt;.csproj&lt;/code&gt; will be included, so make sure you’ve set those up as well.&lt;/p&gt;
&lt;h3 id=&quot;jetbrains-rider&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#jetbrains-rider&quot;&gt;Jetbrains Rider&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rider is my go-to for Jypeli projects. It’s fast, doesn’t get in the way, and makes building executables pretty painless. You’ll need the .NET 8.0 or .NET 10 SDK installed first. You should obviously also grab the &lt;a href=&quot;https://www.jetbrains.com/rider/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rider&lt;/a&gt; non-commercial version from their website.&lt;/p&gt;
&lt;p&gt;Rider will also read your &lt;code&gt;.csproj&lt;/code&gt;, so make sure it’s set up correctly.&lt;/p&gt;
&lt;p&gt;To build a self-contained Windows &lt;code&gt;.exe&lt;/code&gt;, set up a publish configuration:&lt;/p&gt;
&lt;ol class=&quot;list&quot;&gt;
&lt;li&gt;
&lt;p&gt;In the top menu, go to &lt;strong&gt;Run&lt;/strong&gt; → &lt;strong&gt;Edit Configurations&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click the &lt;strong&gt;+&lt;/strong&gt; button and select &lt;strong&gt;.NET: Publish to Folder&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fill in the options:&lt;/p&gt;
&lt;ul class=&quot;list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Target location&lt;/strong&gt;: &lt;code&gt;/path/to/your/build/folder&lt;/code&gt; or wherever you want the final build&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configuration&lt;/strong&gt;: &lt;code&gt;Release | Any CPU&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target framework&lt;/strong&gt;: &lt;code&gt;net8.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target runtime&lt;/strong&gt;: &lt;code&gt;win-x64&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Enable ReadyToRun compilation&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Trim unused assemblies&lt;/strong&gt;: &lt;code&gt;false&lt;/code&gt; → The game won’t run if you set this to true.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Produce single file&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include native libraries for self-extract&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Include all content for self-extract&lt;/strong&gt;: &lt;code&gt;true&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Delete existing files&lt;/strong&gt;: optional, but setting it to &lt;code&gt;true&lt;/code&gt; keeps the folder clean. Will delete your files if you’re not careful.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Once saved, just run the config and you’ll get a single &lt;code&gt;.exe&lt;/code&gt; in your target folder.&lt;br /&gt;
You can delete the &lt;code&gt;.pdb&lt;/code&gt;, the .exe will work standalone.&lt;/p&gt;
&lt;p&gt;This has the .NET runtime bundled, so the file size will be considerable, but at least it’s a single .exe that will run on most Windows machines!&lt;/p&gt;
&lt;h2 id=&quot;building-for-macos&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#building-for-macos&quot;&gt;Building for MacOS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Building a Jypeli for Mac is relatively simple. There’s just one massive caveat—&lt;em&gt;&lt;strong&gt;signing and notarisation require a paid Apple developer license.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It’s not the end of the world, you can still build and distribute your app for free. Your users just have to jump through a few hoops if you’re not going to shell out the $99 a year for the developer license.&lt;/p&gt;
&lt;p&gt;Apple is pretty anal when it comes to unsigned applications, meaning that the executables get a quarantine parameter added. To the end user this shows up as a warning that the app can be malicious or even corrupted with a suggestion to delete it. Not ideal!&lt;/p&gt;
&lt;p&gt;Let’s look at the building and bundling first though!&lt;/p&gt;
&lt;h3 id=&quot;dotnet-publish&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#dotnet-publish&quot;&gt;dotnet publish&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Install the .NET 8.0 SDK from &lt;a href=&quot;https://dotnet.microsoft.com/en-us/download&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://dotnet.microsoft.com/en-us/download&lt;/a&gt;. Make sure you’re grabbing the correct one for your architechture, either arm64 or x64. Then open up the terminal and navigate to your project folder.&lt;/p&gt;
&lt;p&gt;If you’re using an Apple Silicon based Mac, run this command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;dotnet publish &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; Release &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; osx-arm64 --self-contained &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; /p:PublishSingleFile&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;false /p:IncludeNativeLibrariesForSelfExtract&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;if you’re on an older Intel based Mac, replace the &lt;code&gt;osx-arm64&lt;/code&gt; with &lt;code&gt;osx-x64&lt;/code&gt;. This will work with Mac’s running MacOS 10.12 Sierra or later.&lt;/p&gt;
&lt;p&gt;This should create a folder &lt;code&gt;/bin/Release/net8.0/osx-arm64/publish&lt;/code&gt; with a ton of files. Try to execute the $GameName executable file in the directory. You should see your terminal pop up and the game window starting.&lt;/p&gt;
&lt;p&gt;You could zip this up and share with your users, but it isn’t the most user friendly format to run. So, let’s make an app bundle from it!&lt;/p&gt;
&lt;h3 id=&quot;bundling-manually&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#bundling-manually&quot;&gt;Bundling manually&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;An app bundle, aka &lt;em&gt;yourgame.app&lt;/em&gt; is actually just a collection of nested folders with some metadata. It looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;MyApp.app
├── Contents
│   ├── MacOS
│   │   └── MyApp               &lt;span class=&quot;token comment&quot;&gt;# Main executable file&lt;/span&gt;
│   ├── Resources
│   │   └── icon.icns           &lt;span class=&quot;token comment&quot;&gt;# App icon&lt;/span&gt;
│   └── Info.plist              &lt;span class=&quot;token comment&quot;&gt;# App metadata and configuration&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, to get started, let’s create the folder structure.&lt;/p&gt;
&lt;p&gt;You can make the folders manually by hand, remember to name the topmost folder with the .app extension and use right click to &lt;em&gt;“show package contents”&lt;/em&gt; to get inside the app bundle. Or you can use this oneliner:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; MyApp.app/Contents/&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;MacOS,Resources&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;touch&lt;/span&gt; MyApp.app/Contents/Info.plist&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Move every file from the &lt;code&gt;/bin/Release/net8.0/osx-arm64/publish&lt;/code&gt; inside the &lt;code&gt;MyApp.app/Contents/MacOS&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;For the icon, you’ll need a 1024x1024 pixel sized png image. Then run this command&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; icon.iconset &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; sips &lt;span class=&quot;token parameter variable&quot;&gt;-z&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; your-icon.png &lt;span class=&quot;token parameter variable&quot;&gt;--out&lt;/span&gt; icon.iconset/icon_512x512.png &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; your-icon.png icon.iconset/icon_512x512@2x.png &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; iconutil &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; icns icon.iconset &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt; icon.icns &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; icon.iconset&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will take &lt;code&gt;your-icon.png&lt;/code&gt;, create a downscaled 512x512 png and copy your icon to a 512x512@2 retina version of the icon and create an &lt;code&gt;icns&lt;/code&gt; file from both of the images.&lt;/p&gt;
&lt;p&gt;Now, move the created &lt;code&gt;icon.icns&lt;/code&gt; into the &lt;code&gt;MyApp.app/Contents/Resources&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;Lastly, we’ll fill in the &lt;code&gt;info.plist&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;/span&gt;
&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;plist&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;PUBLIC&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;-//Apple//DTD PLIST 1.0//EN&quot;&lt;/span&gt; 
  &lt;span class=&quot;token string&quot;&gt;&quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;plist&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundleName&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;${APP_NAME}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundleExecutable&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;${APP_NAME}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundleIdentifier&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;com.${PUBLISHER}.${APP_NAME}&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundleVersion&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;1.0.1&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundlePackageType&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;APPL&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;CFBundleIconFile&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;icon&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;dict&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;plist&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fill in the &lt;code&gt;${APP_NAME}&lt;/code&gt; fields with your app name as well as &lt;code&gt;com.${PUBLISHER}.${APP_NAME}&lt;/code&gt;, your publisher name.&lt;/p&gt;
&lt;p&gt;The last field, &lt;code&gt;&amp;lt;string&amp;gt;icon&amp;lt;/string&amp;gt;&lt;/code&gt; refers to your app icon. Make sure the value &lt;code&gt;icon&lt;/code&gt;is changed to whatever you named your icns file as without the icns extension.&lt;/p&gt;
&lt;p&gt;You know what? You should have a fully functional app bundle now! Just drag the created &lt;code&gt;MyApp.app&lt;/code&gt; to your &lt;code&gt;Applications/&lt;/code&gt; folder and you’re good to go! Check out the part on &lt;a href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#removing-the-app-from-quarantine&quot;&gt;removing the app from the quarantine&lt;/a&gt; at the end though!&lt;/p&gt;
&lt;h3 id=&quot;bundling-script&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#bundling-script&quot;&gt;Bundling script&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I also made a simple script to automate the creationg of the app bundle. If you’re doing multiple builds, it’ll get tedious creating the bundle by hand every time so a script like this will save some serious time!&lt;/p&gt;
&lt;p&gt;Save the following as &lt;code&gt;build.sh&lt;/code&gt; in the same folder as your &lt;code&gt;.sln&lt;/code&gt; file. Change the &lt;em&gt;“MyApp”&lt;/em&gt; to whatever your game is called and &lt;em&gt;“YourName”&lt;/em&gt; to a single publisher name you want to use.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token shebang important&quot;&gt;#!/bin/bash&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Set app name&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;APP_NAME&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;MyApp&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Set up publisher name&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;PUBLISHER&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;YourName&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Set up app directory&lt;/span&gt;
&lt;span class=&quot;token assign-left variable&quot;&gt;APP_DIR&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;release/&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;.app&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 1. Build the project&lt;/span&gt;
dotnet publish &lt;span class=&quot;token parameter variable&quot;&gt;-c&lt;/span&gt; Release &lt;span class=&quot;token parameter variable&quot;&gt;-r&lt;/span&gt; osx-arm64 --self-contained &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt; /p:PublishSingleFile&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;false /p:IncludeNativeLibrariesForSelfExtract&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;true

&lt;span class=&quot;token comment&quot;&gt;# 2. Clean up any existing .app&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 3. Create .app structure&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/Resources&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 4. Move published files into MacOS directory&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-R&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bin/Release/net8.0/osx-arm64/publish/&quot;&lt;/span&gt;* &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS/&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 5. Copy icon to Resources&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cp&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bin/Release/net8.0/osx-arm64/publish/Content/app.icns&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/Resources/&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# Copy the rest of Content (excluding app.icns) to MacOS/Content&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS/Content&quot;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rsync&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;--exclude&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;app.icns&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bin/Release/net8.0/osx-arm64/publish/Content/&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS/Content/&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 6. Create Info.plist&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/Info.plist&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;EOF
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&amp;lt;!DOCTYPE plist PUBLIC &quot;-//Apple//DTD PLIST 1.0//EN&quot; 
  &quot;http://www.apple.com/DTDs/PropertyList-1.0.dtd&quot;&gt;
&amp;lt;plist version=&quot;1.0&quot;&gt;
&amp;lt;dict&gt;
    &amp;lt;key&gt;CFBundleName&amp;lt;/key&gt;
    &amp;lt;string&gt;&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;&amp;lt;/string&gt;
    &amp;lt;key&gt;CFBundleExecutable&amp;lt;/key&gt;
    &amp;lt;string&gt;&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;&amp;lt;/string&gt;
    &amp;lt;key&gt;CFBundleIdentifier&amp;lt;/key&gt;
    &amp;lt;string&gt;com.&lt;span class=&quot;token variable&quot;&gt;${PUBLISHER}&lt;/span&gt;$.&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;&amp;lt;/string&gt;
    &amp;lt;key&gt;CFBundleVersion&amp;lt;/key&gt;
    &amp;lt;string&gt;1.0.1&amp;lt;/string&gt;
    &amp;lt;key&gt;CFBundlePackageType&amp;lt;/key&gt;
    &amp;lt;string&gt;APPL&amp;lt;/string&gt;
    &amp;lt;key&gt;CFBundleIconFile&amp;lt;/key&gt;
    &amp;lt;string&gt;icon&amp;lt;/string&gt;
&amp;lt;/dict&gt;
&amp;lt;/plist&gt;
EOF&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 7. Rename main binary to match app name&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS/&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;&quot;&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/Contents/MacOS/&lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;&quot;&lt;/span&gt;

&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;✅ &lt;span class=&quot;token variable&quot;&gt;${APP_NAME}&lt;/span&gt;.app created at &lt;span class=&quot;token variable&quot;&gt;$APP_DIR&lt;/span&gt;/&quot;&lt;/span&gt;

&lt;span class=&quot;token comment&quot;&gt;# 8. Cleanup bin directory&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;rm&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-rf&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;bin&quot;&lt;/span&gt;
&lt;span class=&quot;token builtin class-name&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;🧹 Cleaned up build artifacts.&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The script assumes your &lt;code&gt;icon.icns&lt;/code&gt;is located in your Jypeli &lt;code&gt;Contents&lt;/code&gt; directory and is set to always output it in your &lt;code&gt;.csproj&lt;/code&gt; like so:&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;None&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Content&#92;icon.icns&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;CopyToOutputDirectory&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Always&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, run the following command to allow executing the script and then run the script.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; +x build.sh
./build.sh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In short, fill out the two variable names at the start of the script and make sure your icns is output by the build. Run the script and you’ll have the finished executable in your &lt;code&gt;release/&lt;/code&gt; directory, next to your &lt;code&gt;.sln&lt;/code&gt; file.&lt;/p&gt;
&lt;h3 id=&quot;removing-the-app-from-quarantine&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#removing-the-app-from-quarantine&quot;&gt;Removing the app from quarantine&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Assuming you’re not signing and notarising the app, Apple will flag the app stopping your players from starting the game.&lt;/p&gt;
&lt;p&gt;The fix is literally one single terminal command.&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;xattr &lt;span class=&quot;token parameter variable&quot;&gt;-rd&lt;/span&gt; com.apple.quarantine /path/to/MyApp.app&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of typing the path to the app, it’s also possible to write out the start of the command and then dragging the app file into the terminal window. The path will automatically added to the command. After hitting enter, the file will be removed from quarantine and should be executable by the players!&lt;/p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/building-jypeli-executables-on-windows-and-mac/#final-thoughts&quot;&gt;Final thoughts&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There you have it. As you can see, you have a few options when it comes to building your Jypeli games for distribution. There are some caveats with each option, but hopefully I showed you how to exercise your options should you choose one.&lt;/p&gt;
&lt;p&gt;Happy gaming!&lt;/p&gt;

    </content>
    <summary>Creating nice executables for Jypeli games.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Generating content driven CSS with Eleventy</title>
    <link href="https://httpster.io/article/generating-content-driven-css-with-eleventy/" />
    <updated>2025-04-11T00:00:00Z</updated>
    <id>https://httpster.io/article/generating-content-driven-css-with-eleventy/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;If you’ve ever taken a peek at my &lt;a href=&quot;https://httpster.io/main&quot;&gt;content stream&lt;/a&gt;, you’ll know that I use an assortment of colours to denote post categories.&lt;/p&gt;
&lt;p&gt;It took me a while to nail down how to achieve it. Creating the feature was surprisingly simple though once I had an understanding of the data cascade and how to utilize template files.&lt;/p&gt;
&lt;p&gt;The first version used hard-coded templates for each post type. The second version loaded different post types dynamically based on category. Third version inlined dynamically created classes (which meant a lot of duplicated inline CSS) and my latest iteration now creates the classes needed on the fly and everything only gets created once.&lt;/p&gt;
&lt;p&gt;I’ll demonstrate how I did it.&lt;/p&gt;
&lt;h2 id=&quot;directory-data-files&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#directory-data-files&quot;&gt;Directory data files&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Eleventy has a handy thing called Directory data files&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;. They’re JSON or JS files that can either compute or apply static values to the files in your directories.&lt;/p&gt;
&lt;p&gt;My content is separated into sub-folders. I have a &lt;code&gt;src/content/$content-type&lt;/code&gt; layout for my categories, &lt;code&gt;$content-type&lt;/code&gt; being my folders for the categories like &lt;code&gt;articles&lt;/code&gt; or &lt;code&gt;projects&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you create a &lt;code&gt;folder-name.json&lt;/code&gt; file inside the similarily named directory, you can use that json file to prepopulate your YAML front matter. This means, you don’t have to type &lt;code&gt;category: article&lt;/code&gt; for every post you have. It’s pretty nice. This is what my &lt;code&gt;projects.json&lt;/code&gt; looks like:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;layout&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;post&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;category&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;project&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;permalink&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;//project/{{ title | slugify }}/index.html&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;&quot;theme&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;blue&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;light&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So, this means that every post that is in &lt;code&gt;src/content/projects/&lt;/code&gt; will get the specified layout, category, permalink and theme automatically set in the front matter for each post.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;n.b.&lt;/strong&gt; remember the data cascade&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;. If you set a value in your front matter in both the directory data file as well as the front matter in your layouts, the directory file will override the values. Use eleventyComputed to override the directory data file values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;css-variables&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#css-variables&quot;&gt;CSS Variables&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the JSON example above, I set a key value pair called &lt;strong&gt;theme&lt;/strong&gt; with an array as the value. This means that in my layouts I can use either &lt;code&gt;theme[0]&lt;/code&gt; and &lt;code&gt;theme[1]&lt;/code&gt; or &lt;code&gt;post.data.theme[0]&lt;/code&gt; and &lt;code&gt;post.data.theme[1]&lt;/code&gt; to access the values set. You could have more values or just one. If you’re using just one, you don’t need an array, you can simply give it a string value as well.&lt;/p&gt;
&lt;p&gt;In my case, the colour &lt;code&gt;blue&lt;/code&gt; and &lt;code&gt;light&lt;/code&gt; are definied as a CSS variables and I’m only using colours I’ve already named and defined in the CSS like so:&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;:root&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-dark&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #0c0c0c&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-light&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #F3F3F3&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-red&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #e5633e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-turquoise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #1ed397&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-green&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #59D376&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-yellow&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #fdb320 &lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-tangerine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f18b2f&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-orange&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #f79f28&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-blue&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #1E29F9&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;--colour-purple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #4f0eb8&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, for the fun parts!&lt;/p&gt;
&lt;h2 id=&quot;template-file-as-css-and-dynamic-css&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#template-file-as-css-and-dynamic-css&quot;&gt;Template file as CSS and dynamic CSS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The cool thing about Eleventy is the way you can manipulate data and files. CSS is just text and template files are just text as well. As long as you’re properly formatting your templates, you can use any template language Eleventy supports to slurp up all of the data you need and generate files based on that.&lt;/p&gt;
&lt;p&gt;I’m using Nunjucks files as that’s what I’m most familiar with, but I’d recommend going with &lt;code&gt;.11ty.js&lt;/code&gt; files for their flexibility.&lt;/p&gt;
&lt;p&gt;I made a &lt;code&gt;themes.css.11ty.js&lt;/code&gt; file and it looks like this:&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;themes.css.11ty.js&lt;/summary&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;module.exports = class&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;data()&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token selector&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/assets/css/themes.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;token property&quot;&gt;eleventyExcludeFromCollections&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; true&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;token selector&quot;&gt;render(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; collections &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    const seen = new &lt;span class=&quot;token function&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    const themeValues = []&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;token selector&quot;&gt;for (const post of collections.posts)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      const theme = post.data.theme&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;token selector&quot;&gt;if (Array.isArray(theme))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        const key = theme.&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;-&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token selector&quot;&gt;if (!seen.has(key))&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
          seen.&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
          themeValues.&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;token selector&quot;&gt;return themeValues.map(theme =&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token selector&quot;&gt;return `
.theme-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;border-color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[1]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;background-color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.theme-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;:hover,
.theme-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;:focus-within&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;border-color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[1]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;box-shadow: 0.75rem -0.75rem 0 0 var(--color-dark), -0.75rem 0.75rem 0 0 var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.theme-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;::selection&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;background-color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[1]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;.theme-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token selector&quot;&gt;-post-tag&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;color: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[0]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token selector&quot;&gt;background: var(--color-$&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;theme[1]&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      `.&lt;span class=&quot;token function&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;.&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;&#92;n&#92;n&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;details&gt;
&lt;summary&gt;themes.css.njk&lt;/summary&gt;
&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;permalink&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;/assets/css/themes.css&quot;&lt;/span&gt;
&lt;span class=&quot;token literal-property property&quot;&gt;eleventyExcludeFromCollections&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; seenThemes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; uniqueThemes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; post &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; collections&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;posts &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; key &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;-&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;key &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; seenThemes&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; seenThemes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; seenThemes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;key&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;set&lt;/span&gt; uniqueThemes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; uniqueThemes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;post&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; endif &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; endif &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; endfor &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; theme &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; uniqueThemes &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;colour&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  background&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;hover &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  border&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  box&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;shadow&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; 1rem &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;colour&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; theme&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; endfor &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;&lt;em&gt;In short what the snippet above does:&lt;/em&gt;&lt;/p&gt;
&lt;ul class=&quot;list&quot;&gt;
&lt;li&gt;Create a file called themes.css&lt;/li&gt;
&lt;li&gt;Store the theme keys and values&lt;/li&gt;
&lt;li&gt;Loop through the collections.posts and store each unique theme&lt;/li&gt;
&lt;li&gt;For each unique theme, create a theme-$name class and use the theme[0] and theme[1] values for CSS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This will render out to a regular CSS file with all of your themes as their own classes, but you could even take it one step further.&lt;/p&gt;
&lt;p&gt;You could even use a &lt;code&gt;{% if theme[1] == &amp;quot;dark&amp;quot; %}&lt;/code&gt; block to create separate CSS for those themes that work with dark colours and those that work with light colours for example. Or you could randomize the colour values to create a random assortment of themes on each build!&lt;/p&gt;
&lt;h2 id=&quot;using-the-css&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#using-the-css&quot;&gt;Using the CSS&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now it’s time to actually use the CSS we just created.&lt;/p&gt;
&lt;p&gt;First off, you’ll want to include the created file. I also have added a hashing function to cache bust the file between builds.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;  {% set assetHash = global.random() %}
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;/assets/css/themes.css?{{ assetHash }}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my Nunjucks template I can now access the CSS classes like so&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;article&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{% if post.data.theme %}theme-{{ post.data.theme[0] }}{% endif %}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;article&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So in the case of my projects, we’re checking if the project file returns a theme value and then we add the &lt;code&gt;theme-blue&lt;/code&gt; class to the article.&lt;/p&gt;
&lt;p&gt;Remember that if you’re not using themes for all of the content, you’ll need a higher specifity in your classes to override the defaults. My articles have a fallback theme and only if I have set a custom theme in the post, will we be using that.&lt;/p&gt;
&lt;h2 id=&quot;end-words&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#end-words&quot;&gt;End words&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Eleventy can really be such a delight to work with and it’s stuff like this that keeps me coming back to it all the time.&lt;/p&gt;
&lt;p&gt;Hopefully my sort-of tutorial inspires you to experiment with using data and templates to create dynamic CSS on the fly. I’m excited to see what you all come up with!&lt;/p&gt;
&lt;p&gt;Ta ta and farewell!&lt;/p&gt;
&lt;h2 id=&quot;notes&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#notes&quot;&gt;Notes&lt;/a&gt;&lt;/h2&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.11ty.dev/docs/data-template-dir/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.11ty.dev/docs/data-template-dir/&lt;/a&gt; &lt;a href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.11ty.dev/docs/layouts/#sources-of-data&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.11ty.dev/docs/layouts/#sources-of-data&lt;/a&gt; &lt;a href=&quot;https://httpster.io/article/generating-content-driven-css-with-eleventy/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

    </content>
    <summary>Why spend an hour writing CSS when you can spend four hours creating classes on the fly?</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Wheel woes</title>
    <link href="https://httpster.io/article/wheel-woes/" />
    <updated>2025-01-23T00:00:00Z</updated>
    <id>https://httpster.io/article/wheel-woes/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;I had a tiny mishap with the car. When I went to pick up my wife from work last friday, all was well.&lt;/p&gt;
&lt;p&gt;We didn’t get far from the lot when the ride started to feel a tiny bit bumpy. The roads are filled with snow and ice so I didn’t think too much about it, it’s normal to feel a bit bumpy. Still, I kept following the situation. Once we hit a better cleared patch of road and the ride still felt bumpy, I knew something was off and thus, we pulled over.&lt;/p&gt;
&lt;figure class=&quot;mb-xl&quot;&gt;
  &lt;img src=&quot;https://httpster.io/article/wheel-woes/tire.webp&quot; alt=&quot;A car with a flat tire&quot; title=&quot;Screenshot of Github&#39;s UI with the fork-button hilighted&quot; /&gt;
  &lt;figcaption&gt;The sad, flat situation&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Damn, a flat. The time was nearing midnight, it was dark and cold. I didn’t want to damage the car or the rims so we had to leave the car in the parking lot we’d pulled into. Luckily, my parents lived a few minutes walk from where we’d stopped so I popped over, borrowed their car for the night and went home.&lt;/p&gt;
&lt;p&gt;The following morning, it’s saturday. All of the tire shops are closed on the weekend it seems and even if I managed to buy a tire, we’d need someone to install it on the old rim. Anyways, the car was parked on an extremely slippery parking lot that was on an not-so-insignificant sideways incline, which also meant that changing the tire there wasn’t an option.&lt;/p&gt;
&lt;p&gt;We had to tow.&lt;/p&gt;
&lt;p&gt;In my eternal wisdom, I’ve always paid for the &lt;em&gt;second&lt;/em&gt; cheapest insurance which comes with 24/7 free roadside assitance, including tows. The third cheapest would’ve also covered arson and moose accidents.&lt;/p&gt;
&lt;p&gt;I called up the insurance company and within an hour the tow guy arrives. He agrees that changing into the crappy mini spare tire is a bit hazardous as it’s too slippery to jack the car up. He also happens to know that my local go-to tire shop actually does have on-call service on weekends. So, the car gets towed there.&lt;/p&gt;
&lt;p&gt;An hour later I get a call from Janne at &lt;a href=&quot;https://rengasnuora.fi/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Rengasnuora&lt;/a&gt;, he happens to have two almost unused fitting tires for 150 €. This is including the weekend on-call service, changing the tires and the price of &#39;em. Pretty nice considering that a new pair of similar ones would’ve cost me 300 € and normally the changing costs around 50 € in itself. I could’ve also just bought one of the tires but, the other rear tire was about 14 years old at this point and it’s important to have similar tires on both sides of the axle, especially with our winter conditions.&lt;/p&gt;
&lt;p&gt;All in all, this whole episode cost me 150 € and took about two hours of my saturday. I expected a lot worse. If you ever happen to find yourself in tire need &lt;em&gt;(hehe)&lt;/em&gt; of a set of wheels in central Finland, you should call up Janne. ⭐⭐⭐⭐⭐&lt;/p&gt;
&lt;p&gt;Oh, the cause of the flat was a screw on the road. Shit happens, I guess.&lt;/p&gt;

    </content>
    <summary>I didn&#39;t have wheels of steel.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Beware of the productivity illusion</title>
    <link href="https://httpster.io/article/beware-of-the-productivity-illusion/" />
    <updated>2025-01-08T00:00:00Z</updated>
    <id>https://httpster.io/article/beware-of-the-productivity-illusion/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;I set out to write a simple &lt;em&gt;“New Year, new me”&lt;/em&gt; type of blog post. Bish bash bosh, done and dusted, right? Nope!&lt;/p&gt;
&lt;p&gt;After booting up VS Code, I remembered seeing on Robb’s &lt;a href=&quot;https://lens.rknight.me/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Lens&lt;/a&gt; website that my RSS feed was missing the proper meta tag. While looking up how to correctly set it up I fell into the trap.&lt;/p&gt;
&lt;video width=&quot;480&quot; height=&quot;480&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
  &lt;source src=&quot;https://httpster.io/assets/media/birds.webm&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;
&lt;p&gt;I can reveal now that I didn’t write that blog post, not a single word. I did however fix my RSS and added two additional feeds that are fully validated, so now you can subscribe to my nonexistant content with Atom, RSS and JSON feeds :D. I also created a new Eleventy filter for my website and did some CSS tidying as I found some broken behavior with images.&lt;/p&gt;
&lt;p&gt;Ironically, this post was written on my phone at 10 a.m. after shutting off my desktop PC and giving up for the night &lt;em&gt;(day, morning w/e, sleep patterns are a scam by Big Sleep™)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The thing about this type of &lt;em&gt;&lt;strong&gt;“productivity”&lt;/strong&gt;&lt;/em&gt; is that it’s not very productive at all. I didn’t accomplish the task I set out to do. I did get a lot of things done, but I didn’t work on anything I actually needed to do. I didn’t even really have the opportunity to make a choice at any point, I kinda just slipped into gear of working on unrelated semi-adjacent issues. This is pretty common with ADHD and really quite annoying.&lt;/p&gt;
&lt;p&gt;I don’t like not having the option to choose, I don’t want to get swept away because I can’t decide what to focus on.&lt;/p&gt;
&lt;p&gt;If this resonated with you or you have suggestions on what I could try, please feel free to shoot me a message!&lt;/p&gt;

    </content>
    <summary>I fell for it once again.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Family gatherings</title>
    <link href="https://httpster.io/article/family-gatherings/" />
    <updated>2024-07-17T00:00:00Z</updated>
    <id>https://httpster.io/article/family-gatherings/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;I’m usually not a fan of big family gatherings. You know the type, every aunt and their neighbour is invited to some tiny town half-way across the country and then you sit there trying to small talk about the most inane topics. Usually it’s some kid is getting christened or an uncle turns 80 years old. Dunno.&lt;/p&gt;
&lt;p&gt;I don’t mind the extended family, cousins, uncles and whatnot. They’re alright people, but I’m not really close with them either and we share nothing in common apart from being distantly related.&lt;/p&gt;
&lt;p&gt;Today we met up with my cousin and his family. I haven’t seen them in a decade and to my surprise, it was alright. The kids are more grown up and we could actually chat. The kids also brought their partners who seemed like decent fellows so that’s nice.&lt;/p&gt;
&lt;p&gt;Driving for four hours to hang out and grill a bit isn’t still fun and I’m absolutely knackered, but expectations were at least exceeded.&lt;/p&gt;

    </content>
    <summary>Surprisingly okay this time.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Wedding stress</title>
    <link href="https://httpster.io/article/wedding-stress/" />
    <updated>2024-07-15T00:00:00Z</updated>
    <id>https://httpster.io/article/wedding-stress/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;You know what’s funny? When I got married two years ago, I had a lovely old time. Me and the wife put the wedding together mostly entirely by ourselves.&lt;/p&gt;
&lt;p&gt;We did get a bit of help from my family, mainly with setting up the venue, running the kitchen &lt;em&gt;(making coffee in other words)&lt;/em&gt; and cleaning up the venue the following day.&lt;/p&gt;
&lt;p&gt;It was very stress-free and simple. We had no expectations for our family, they kinda just helped with whatever they felt like. There wasn’t a ton to do.&lt;/p&gt;
&lt;p&gt;So you can guess my surprise when being the bestman for my brother turns out to be quite the opposite of easy or relaxing. There’s a lot more coordination and planning to be done, I have more tasks than I had at my own wedding. I still haven’t written the speech and it’s less than a week away!&lt;/p&gt;
&lt;p&gt;It kinda makes sense why this is stressing me out. I don’t have a clear picture of the upcoming wedding as it’s not my own. I don’t know what to expect and therefore I can’t plan anything ahead, I don’t know what’s to be expected as I can’t read anyone’s mind.&lt;/p&gt;
&lt;p&gt;My wife also said something very similar to me just today, so I guess I’m not alone with the feeling. Luckily, in less than a weeks time it’s over and I can finally relax. But, before that I do have a ton of things to do.&lt;/p&gt;

    </content>
    <summary>Why are weddings so stressful?!?!</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>The interweb sucks</title>
    <link href="https://httpster.io/article/the-interweb-sucks/" />
    <updated>2024-07-08T00:00:00Z</updated>
    <id>https://httpster.io/article/the-interweb-sucks/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;intro&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#intro&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The internet annoys the hecc out of me. Almost on the daily, I’m bemoaning the endlessly enshittificated&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; websites and AI slop&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; shoved at me through every crack and crevice possible. It might just be nostalgia talking, but it feels like things used to be better.&lt;/p&gt;
&lt;p&gt;A decade or two ago, we had a good thing going. Forums used to be a thing; you could literally find a bunch of people nerding out on stuff like Final Fantasy lore &lt;em&gt;(R.I.P. FFFin)&lt;/em&gt; and rhythm games, or you could just jump in a random IRC channel and make new friends.&lt;/p&gt;
&lt;p&gt;People created these tiny little tribes left and right, and the door tended to be wide open. &lt;em&gt;Come on in, be yourself.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Even social media back then felt more authentic. Facebook actually showed you what your twice-removed aunt did over the weekend, and you could listen to the shitty 64kbps mp3 that the weird Midwest emo punk band you follow on MySpace just released.&lt;/p&gt;
&lt;p&gt;Simpler times.&lt;/p&gt;
&lt;h2 id=&quot;when-did-it-go-wrong&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#when-did-it-go-wrong&quot;&gt;When did it go wrong?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When &lt;em&gt;&lt;strong&gt;did&lt;/strong&gt;&lt;/em&gt; it go wrong? I don’t know exactly when, but sometime in the past decade, I’ve started to feel increasingly anxious when I’m online.&lt;/p&gt;
&lt;p&gt;A big part of it is the feeling of having lost my tribe.&lt;/p&gt;
&lt;p&gt;Facebook, Reddit, Discord, and the like slurped every little independent site up. Communities moved to bigger platforms where they didn’t have to worry about hosting, and it was easier to gain new users as you had access a metric tonne of other users already using the service.&lt;/p&gt;
&lt;p&gt;Forums closed, IRC channels dried up, and slowly but surely, your buddies didn’t come in online anymore. I felt less inclined to participate myself as well, exacerbating the problem ironically.&lt;/p&gt;
&lt;h2 id=&quot;centralization&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#centralization&quot;&gt;Centralization&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In itself, I don’t think the centralization wasn’t the main issue. New communities could and would pop up on these bigger platforms.&lt;/p&gt;
&lt;p&gt;For me, it felt like all these communities had lost their personality. Flair, charm, &lt;em&gt;je ne sais quoi&lt;/em&gt;, whatever you want to call it. They went from being the homeowners to being renters. New rules, new management, and the keys to the kingdom had been handed over.&lt;/p&gt;
&lt;p&gt;This also meant that users &lt;em&gt;(like me)&lt;/em&gt; could afford to be lazy. Why scour the deep plunges of the interwebs when Reddit had n+1 different subcommunities to peruse?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;When you mix lazy users, homogenised communities with profit-seeking big corporations, and engagement optimising algorithms, you get a massive turd.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;websites-are-built-to-suck&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#websites-are-built-to-suck&quot;&gt;Websites are built to suck&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Anyone who has talked with me for more than two minutes knows that I’m as anti-capitalistic and anti-establishment as they come. Which is why I’m sad when every website I’m visiting is:&lt;/p&gt;
&lt;ul class=&quot;list&quot;&gt;
&lt;li&gt;riddled with ads,&lt;/li&gt;
&lt;li&gt;trying to sell me stuff,&lt;/li&gt;
&lt;li&gt;harvesting every tidbit of my existence to sell to someone else.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Usually it’s some unholy amalgamation of all the above.&lt;/p&gt;
&lt;p&gt;Case in point, you could amuse or depress yourself with User Inyerface&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;, how-i-experience-web-today&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; or Cookie Consent Speedrun&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;I don’t mind the European Union. I think they mainly aim to do good things. But if we look at GDPR and cookie consent laws, and how these seemingly good ideas have manifested themselves into a huge shitshow in terms of implementation, I can’t help but feel doubly sad.&lt;/p&gt;
&lt;h2 id=&quot;no-human-curation-4-u&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#no-human-curation-4-u&quot;&gt;no human curation 4 u&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I respect people who curate stuff. &lt;em&gt;&lt;strong&gt;The Librarian&lt;/strong&gt;&lt;/em&gt; type is cool. In every community I’ve been part of, there’s always been &lt;em&gt;&lt;u&gt;that&lt;/u&gt;&lt;/em&gt; quiet person who squirrels away every bit of useful information into some archive for the greater good.&lt;/p&gt;
&lt;p&gt;Another type would be &lt;em&gt;&lt;strong&gt;The Tastemaker&lt;/strong&gt;&lt;/em&gt;. People who trawled through copious amounts of content to pick the shiniest gems to share with you. I’ve done my fair bit myself as well, rather successfully, if I might add.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;“Fuck that!”&lt;/strong&gt;&lt;/em&gt; said every online media platform, I guess. Why spend time and effort &lt;em&gt;(read: money)&lt;/em&gt; curating when they could just surface the SEO spamming sites or those who spend the biggest of bucks to push their unrelated advertised content?&lt;/p&gt;
&lt;p&gt;Instead of showing me content I actually want, I’m offered content that either riles me up&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn6&quot; id=&quot;fnref6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt; or earns them the most money. Whatever the content, I’m not coming out on top; my needs aren’t met.&lt;/p&gt;
&lt;p&gt;To make matters even worse, now we have to deal with this lazily produced AI shit, aka. &lt;em&gt;&lt;strong&gt;slop&lt;/strong&gt;&lt;/em&gt;. It’s not even human-generated SEO spam, where a human has spent an iota of thought into what and how they should spam. Let’s just remove the human from the production side of things and push slop to the masses.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I am Jack’s triply sad occipital lobe.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Why not remove the human entirely from the equation? Soon, Windows’ Copilot™ AI will browse the internet for me &lt;em&gt;(I’ll have no choice in this)&lt;/em&gt; and summarise everything that’s pertinent &lt;em&gt;(what Satya Nadella allows me to know)&lt;/em&gt;, and ChatGPT will have hallucinated some mind-altering facts I’ll base my whole new life on in a sick game of Chinese whispers. I’ll have learnt nothing; my opinions are decided for me, and my serotonin-starved brains are left begging for more.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Pls Google, can I haz some more cat pictures?&lt;/em&gt;&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn7&quot; id=&quot;fnref7&quot;&gt;[7]&lt;/a&gt;&lt;/sup&gt; The internet is dead&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn8&quot; id=&quot;fnref8&quot;&gt;[8]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;h2 id=&quot;thank-dog-for-the-indieweb&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#thank-dog-for-the-indieweb&quot;&gt;Thank dog for the Indieweb&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Luckily, there’s still a tiny sliver of hope. There are people working on more independent, isolated, but connected, online tools and websites. People like Adam&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn9&quot; id=&quot;fnref9&quot;&gt;[9]&lt;/a&gt;&lt;/sup&gt; are creating their own communities and allowing people some semblance of control over their online presence.&lt;/p&gt;
&lt;p&gt;There’s the fediverse&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn10&quot; id=&quot;fnref10&quot;&gt;[10]&lt;/a&gt;&lt;/sup&gt; with its’ mainstream alternatives like Mastodon, Pixelfeed, Lemmy, etc. and there are also people like Robb&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn11&quot; id=&quot;fnref11&quot;&gt;[11]&lt;/a&gt;&lt;/sup&gt; doing their part in stopping LLMs from slurping up every bit of data from the internet.&lt;/p&gt;
&lt;p&gt;There’s people like Jeremy&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn12&quot; id=&quot;fnref12&quot;&gt;[12]&lt;/a&gt;&lt;/sup&gt; who are much more adept at sharing their thoughts on complex issues than I am.&lt;/p&gt;
&lt;p&gt;And obviously, there’s me. I just want to make silly&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn13&quot; id=&quot;fnref13&quot;&gt;[13]&lt;/a&gt;&lt;/sup&gt; things&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fn14&quot; id=&quot;fnref14&quot;&gt;[14]&lt;/a&gt;&lt;/sup&gt; online. I just hope that that counts for something.&lt;/p&gt;
&lt;h2 id=&quot;notes&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/the-interweb-sucks/#notes&quot;&gt;Notes&lt;/a&gt;&lt;/h2&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://www.ft.com/content/6fb1602d-a08b-4a8c-bac0-047b7d64aba5 &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://simonwillison.net/2024/May/8/slop/ &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://userinyerface.com &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://how-i-experience-web-today.com/detail &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://cookieconsentspeed.run &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://lens.monash.edu/@politics-society/2022/05/30/1384596/facebook-and-the-unconscionability-of-outrage-algorithms &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn7&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://www.youtube.com/watch?v=vNxEQdntdFo &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref7&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn8&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://theconversation.com/the-dead-internet-theory-makes-eerie-claims-about-an-ai-run-web-the-truth-is-more-sinister-229609 &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref8&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn9&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://omg.lol &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref9&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn10&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://www.theverge.com/24063290/fediverse-explained-activitypub-social-media-open-protocol &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref10&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn11&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://rknight.me/blog/perplexity-ai-is-lying-about-its-user-agent/ &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref11&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn12&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://adactio.com/journal/21241 &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref12&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn13&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://hevonen.httpster.io &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref13&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn14&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://mainstreamsheep.bandcamp.com &lt;a href=&quot;https://httpster.io/article/the-interweb-sucks/#fnref14&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

    </content>
    <summary>Pining for the yesteryears.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Symbol film review</title>
    <link href="https://httpster.io/review/symbol-film-review/" />
    <updated>2024-06-26T00:00:00Z</updated>
    <id>https://httpster.io/review/symbol-film-review/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;intro&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/symbol-film-review/#intro&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Hitoshi Matsumoto is a Japanese comedy legend most well known for his work in Gaki no Tsukai&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; and as the boke&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; of the comedy duo Downtown. His second film, &lt;em&gt;Symbol&lt;/em&gt;, is definitely a weird one to say the least.&lt;/p&gt;
&lt;p&gt;After finishing the movie, I shouldn’t have been surprised to learn that not only did Matsumoto star as the main character in the film, he also wrote and directed it himself.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/review/symbol-film-review/screen2.webp&quot; alt=&quot;Screenshot from the film Symbol. Hitoshi Matsumoto&#39;s character is laying in a white room in a yellow and dotted pajamas, his eyes are open and glassy.&quot; title=&quot;Screenshot from the film Symbol. Hitoshi Matsumoto&#39;s character is laying in a white room in a yellow and dotted pajamas, his eyes are open and glassy.&quot; /&gt;
  &lt;figcaption&gt;Hitoshi Matsumoto&#39;s character, trapped in the white room, waking up for the first time.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;plot&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/symbol-film-review/#plot&quot;&gt;Plot&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Symbol has two separate storylines that seemingly have very little to do with each other. The film starts out in Mexico, where we follow the day of an middle-aged lucha libre&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt; wrestler called Escargot Man and his family as they prepare for Escargot Man’s upcoming fight.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/review/symbol-film-review/screen5.webp&quot; alt=&quot;Screenshot from the film Symbol. An older Mexican lucha libre wrestler in green and red tights wags his index finger while he&#39;s standing outside the wrestling ring. The other wrestler in purple tights has his hands in the air as he challenges the green wrestler.&quot; title=&quot;Screenshot from the film Symbol. An older Mexican lucha libre wrestler in green and red tights wags his index finger while he&#39;s standing outside the wrestling ring. The other wrestler in purple tights has his hands in the air as he challenges the green wrestler.&quot; /&gt;
  &lt;figcaption&gt;Escargot Man is giving Tequila Joe the big no-no.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;In the other storyline, the main character, simply called &lt;em&gt;The Man&lt;/em&gt;, wakes up in a bare, white, room with the walls covered in thousands of little peculiar looking switches.&lt;/p&gt;
&lt;p&gt;Pressing one of the switches, the protagonist learns that each of them do a different thing. One switch might give him a pair of chopsticks, another chucks a bonsai-tree at him. Each press results in escalating madness.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/review/symbol-film-review/screen4.webp&quot; alt=&quot;Screenshot from the film Symbol. The main character is in the white room with the switches covering the right side of the wall. There is one piece of fish on top of one of the switches and a metal legged chair tipped over in the background. The main character is squatting with one knee on the ground and looking as if he&#39;s deep in thought.&quot; title=&quot;Screenshot from the film Symbol. The main character is in the white room with the switches covering the right side of the wall. There is one piece of fish on top of one of the switches and a metal legged chair tipped over in the background. The main character is squatting with one knee on the ground and looking as if he&#39;s deep in thought.&quot; /&gt;
  &lt;figcaption&gt;A plan starts to formulate.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Without giving too much of the plot away, the storylines do eventually converge in an unexpected fashion.&lt;/p&gt;
&lt;h2 id=&quot;production-and-writing&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/symbol-film-review/#production-and-writing&quot;&gt;Production and writing&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The scenes in Mexico look quite good production-wise, despite suffering from the yellow and orange colour grading trope. The writing and acting is more based on realism and there’s an understated humor and wit to it. It reminds me a bit of Quentin Dupieux’s Rubber&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; The milieu in Mexico is run-down and grimy as we follow the family’s anxious preparations for the upcoming fight.&lt;/p&gt;
&lt;p&gt;You can count the lines of dialogue with the fingers on your two hands and still have a few to spare, there isn’t a need for lengthy exchanges as the cinematography does most of the talking.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/review/symbol-film-review/screen1.webp&quot; alt=&quot;Screenshot from the film Symbol. A nun with sunglasses, played by Adriana Fricke, is driving an old yellow car in the Mexican desert.&quot; title=&quot;Screenshot from the film Symbol. A nun with sunglasses, played by Adriana Fricke, is driving an old yellow car in the Mexican desert.&quot; /&gt;
  &lt;figcaption&gt;Adriana Fricke as Karen in Symbol.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;On the other hand, the scenes with Matsumoto in the white room are almost from an entirely different film. The colors are bright, light and pastel, the mood is almost sterile and clinical as we look at the main character trying to make sense of his surroundings. Almost like studing a lab rat.&lt;/p&gt;
&lt;p&gt;The Matsumoto scenes are aided by CGI that isn’t looking too stellar by modern standards but if we consider that the film came out NaN years ago, I think it’s aged just fine. The film is easy on the eye in general.&lt;/p&gt;
&lt;p&gt;Matsumoto’s character is very vocal and outspoken compared to his Mexican counterparts, despite being all alone in the room. He reacts loudly to his surroundings and his pleas and cries cannot be taken seriously at all. The delivery of every joke and beat is perfect. There’s just enough—&lt;em&gt;but not too much&lt;/em&gt;—pause between the action and reaction and it’s obvious that there’s a comedy legend behind the movie.&lt;/p&gt;
&lt;p&gt;I think the pacing of the movie works well. It’s not a super slow burner but it’s not filled to the brim with action either. Both storylines progresses and keep viewer engaged well enough. It’s definitely attempting to out-weird the viewer and much of its’ charm comes from the WTF factor of the events. But that’s how I like my movies anyways.&lt;/p&gt;
&lt;h2 id=&quot;final-conclusions&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/symbol-film-review/#final-conclusions&quot;&gt;Final conclusions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Symbol isn’t a film I’d recommend to everyone, It’s definitely made for the acquired taste. On the other hand, if you enjoy the occasional juvenile joke, physical comedy and absurd and surreal films in general, Symbol is an excellent film in its’ genre.&lt;/p&gt;
&lt;p&gt;I was thoroughly entertained and glad I ended up watching the movie.&lt;/p&gt;
  &lt;section class=&quot;review-score&quot; style=&quot; background: var(--color-yellow,dark);&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;score&lt;/dt&gt; 
    &lt;dd&gt;87 / 100&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;/section&gt;
&lt;h2 id=&quot;notes&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/symbol-film-review/#notes&quot;&gt;Notes&lt;/a&gt;&lt;/h2&gt;
&lt;hr class=&quot;footnotes-sep&quot; /&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://www.teamgaki.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Team Gaki website&lt;/a&gt; with some subbed episodes to watch. &lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;In manzai comedy, a traditional Japanese form of stand-up comedy, the “boke” is the role of the funny man who makes foolish or absurd statements and actions, which are then corrected or criticized by the “tsukkomi,” the straight man. &lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Lucha libre wrestlers, also known as luchadores, are Mexican professional wrestlers known for their high-flying maneuvers, colorful masks, and theatrical, acrobatic style of wrestling. &lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;Quentin Dupieux’s Rubber movie on IMDb https://www.imdb.com/title/tt1612774/ &lt;a href=&quot;https://httpster.io/review/symbol-film-review/#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;

    </content>
    <summary>Matsumoto&#39;s second film is easily the wackiest one I&#39;ve seen in a long time.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Casiopea&#39;s debut album review</title>
    <link href="https://httpster.io/review/casiopeas-debut-album-review/" />
    <updated>2024-06-21T00:00:00Z</updated>
    <id>https://httpster.io/review/casiopeas-debut-album-review/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;intro&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#intro&quot;&gt;Intro&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;During the COVID lockdowns, me and the wife got into a habit of playing Scrabble or doing puzzles whilst listening to random albums from YouTube.&lt;/p&gt;
&lt;p&gt;I had previously listened quite a bit to some 80s’ cheesy Japanese citypop music, which is why I wasn’t surprised when most of my algorithmic frontpage was mainly that. There was a few channels like Xerf Xpec and Kuma’s Campfire that posted a lot of mixtapes and full albums from artists I’d never hear of before.&lt;/p&gt;
&lt;p&gt;That’s where I heard Casiopea the first time. It was a bit cheesy at first but after having a few of their albums in the background while playing Scrabble, I grew into it. Four years later, Casiopea comprises of roughly 90% of the music I listen to. It’s hands down my favourite band.&lt;/p&gt;
&lt;p&gt;In an effort to spread the love, I’ll try to write a review of each of their albums. I think it’s only fitting to with their debut album, &lt;em&gt;Casiopea&lt;/em&gt; from 1979. If you’ve been on the same side of YouTube as I have, you’ll most likely recognize the iconic album cover with the Lola T290 and March 74S racecars.&lt;/p&gt;
&lt;h2 id=&quot;about-the-album&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#about-the-album&quot;&gt;About the album&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This is Casiopea’s debut album, confusingly also called &lt;em&gt;Casiopea&lt;/em&gt;. It was originally released as an LP record in 1979 and later in 1986 as CD as well. Casiopea had already formed back in 1976 and they competed twice in Yamaha’s amateur band contest, EastWest &#39;76 and &#39;77. In 1979 they managed to get signed to Alfa records which ended up being the label they’ve released a majority of their albums on.&lt;/p&gt;
&lt;p&gt;Funnily enough, in EastWest &#39;77 one of the judges, Yoshihiro Naruse, would years later end up becoming Casiopea’s main basist.&lt;/p&gt;
&lt;p&gt;Originally Casiopea consisted of &lt;strong&gt;Issei Noro&lt;/strong&gt; &lt;em&gt;(guitar)&lt;/em&gt;, &lt;strong&gt;Tetsuo Sakurai&lt;/strong&gt; &lt;em&gt;(bass)&lt;/em&gt;, Hidehiko Koike &lt;em&gt;(keys)&lt;/em&gt; and Tohru Suzuki &lt;em&gt;(drums)&lt;/em&gt; but Koike and Suzuki left the band before the first album and were replaced by &lt;strong&gt;Minoru Mukaiya&lt;/strong&gt; &lt;em&gt;(keys)&lt;/em&gt; and &lt;strong&gt;Takashi Sasaki&lt;/strong&gt; &lt;em&gt;(drums)&lt;/em&gt; respectively.&lt;/p&gt;
&lt;p&gt;This album is also one of the rare albums featuring additional studio band members. In this case, we have brothers Randy and Michael Brecker playing the brass section with David Sanborn.&lt;/p&gt;
&lt;p&gt;There’s five main versions of this album. The original &lt;strong&gt;32XA-104&lt;/strong&gt; CD and &lt;strong&gt;ALR-6017&lt;/strong&gt; LP, &lt;strong&gt;VRCL-2201/2221&lt;/strong&gt; DSD remastered version, 96khz 24bit hi-res FLAC digital version and last year a new alternative mix from 2000 called &lt;strong&gt;TOCT-24364&lt;/strong&gt;, the so-called Millenium edition, was discovered as well.&lt;/p&gt;
&lt;p&gt;The source recordings for all versions is the same, but the mixing differs a bit between the albums.&lt;/p&gt;
&lt;h2 id=&quot;tracklist&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#tracklist&quot;&gt;Tracklist&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;1-time-limit&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#1-time-limit&quot;&gt;1. Time Limit&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Time Limit is the perfect track to get you started on your Casiopea journey. It begins with some simple but groovy drum beats and builds up with some horns until it drops into a jivy bass groove with the brass supporting. We get to enjoy some funky Rhodes solos by Mukaiya.&lt;/p&gt;
&lt;p&gt;The guitar tone on Noro’s guitar riffs drows a bit with the faster picking. Mix wise you can hear the age of the album, in both good and bad. Considering that the guitarist Noro is also the band leader, there’s actually very little guitar in the first track.&lt;/p&gt;
&lt;p&gt;In the middle section when we get into the second &lt;em&gt;“chorus”&lt;/em&gt; we get some solos from the two saxophones and trumpet with the rest of the band offering a driving backing to improvise over. In my opinion the brass stands out a bit too much and I’m really not that keen on saxophones in general, which luckily isn’t a reoccuring instrument in Casiopea’s discography.&lt;/p&gt;
&lt;p&gt;Sasaki offers some very interesting synopations with his drum beats and you can hear how technical his playing is with all the little flourishes here and there.&lt;/p&gt;
&lt;p&gt;Sakurai’s deep bass tones support the drums beautifully and the riffs are kept interesting throughout the track.&lt;/p&gt;
&lt;p&gt;Overall, a great start for the album!&lt;/p&gt;
&lt;h3 id=&quot;2-tears-of-the-star&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#2-tears-of-the-star&quot;&gt;2. Tears Of The Star&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Tears Of The Star is a slower track built around some synths and keys playing a forlorn melody. It is followed with some very careful drumming and some steel-stringed acoustic guitar that add some interest.&lt;/p&gt;
&lt;p&gt;After this the track returns back to the simple melody from the start with the bass playing the main melody and we have some Rhodes organs in the backing adding little flourishes. This slowly builds into some sad and epic strings as the song crescendoes with some bigger piano chords. After the crescendo we return back to beginning, except on a slightly less somber note.&lt;/p&gt;
&lt;p&gt;The song is beautiful and wonderfully moody. Maybe not the easiest Casiopea track to start with but it’ll grown on you after a few listens.&lt;/p&gt;
&lt;h3 id=&quot;3-space-road&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#3-space-road&quot;&gt;3. Space Road&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Space Road is a classic that Casiopea has re-recorded on several of their albums. This might be my favourite song on the whole album as it embodies all the best parts of Casiopea’s later production in such a tight composition.&lt;/p&gt;
&lt;p&gt;The whole vibe of the track is very cosmic and otherworldly. The first minute is a build up with faster percussions combined slower drone like keyboard melodies and a moving bass pattern that builds into a beautiful ensemble of sounds when the guitar comes to bind it all together.&lt;/p&gt;
&lt;p&gt;The break around 2 minutes just adds intensity to the groove as it attempts to bring it down but then it keeps on going until we reach a short breakdown where Noro gets to bring in an intensive guitar solo. The guitar sound and choice of notes is simply just perfection.&lt;/p&gt;
&lt;p&gt;Mukaiya plays some faster keyboard runs that transform into an almost sinister pre-chorus that evolves back into the main section of the song with another great guitar solo that carries through the rest of the song.&lt;/p&gt;
&lt;p&gt;Out of every track on this album, I think this is the best song to showcase Sasaki’s technical forté as he plays some incredibly difficult drum patterns that almost make you question your own sense of rhythm. If the rest of the band couldn’t keep up with the technical drums, I’d almost call it overplaying the drums but as such it fits perfectly. Just listen to those hats!&lt;/p&gt;
&lt;p&gt;Space Road is simply a beautiful journey from start to finish with some incredibly skilled writing and execution. This might be my first choice as a track to introduce someone to Casiopea.&lt;/p&gt;
&lt;h3 id=&quot;4-midnight-rendezvous&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#4-midnight-rendezvous&quot;&gt;4. Midnight Rendezvous&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Another classic that has been released half a dozen of times. The version of Midnight Rendezvous on this album is still one of my favourites though.&lt;/p&gt;
&lt;p&gt;We’re off to a great start with the swinging off-beat drums and bouncing bassline and after a quick build-up Noro introduces his catchy guitar riff that will evoke a very Noir mood. This mood transforms as we reach the chorus and the string section comes in to add some colour to this dark and murky track.&lt;/p&gt;
&lt;p&gt;In the mid-section we get a great little blues organ solo from Mukaiya that carries to another great solo by Noro. We return to another beautiful chorus before the song starts looping the verse as it fades into nothingness.&lt;/p&gt;
&lt;p&gt;I especially like this album’s version as it’s the only one with the string section in the chorus. Casiopea doesn’t really use strings and in this version the strings elevate the song into a whole new place where the later versions don’t go at all.&lt;/p&gt;
&lt;h3 id=&quot;5-far-away&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#5-far-away&quot;&gt;5. Far Away&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;For some reason, this is the least memorable song of the whole album. For a long time I didn’t even remember that it existed.&lt;/p&gt;
&lt;p&gt;The riff that’s playing right from the start somehow doesn’t fit the rest of the album perhaps. It has a bit of a RHCP feel to it. The pacing of the song also feels a bit funny and it feels like it doesn’t really know where to go or what the main catch is.&lt;/p&gt;
&lt;p&gt;It’s not a bad song by any means, it just kinda stands out from the rest and at the same time, doesn’t stand out at all?&lt;/p&gt;
&lt;h3 id=&quot;6-swallow&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#6-swallow&quot;&gt;6. Swallow&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This song is one of the more fast paced songs with a lot of drive behind it. It starts with some faster paced drums with some insane tom fills and lovely hi-hat work. The guitar plays a catchy slow melody while the bass dances around it with insane precision.&lt;/p&gt;
&lt;p&gt;The track never really slows down as the chorus simply builds into a very space invaders type of synth solo while Sakurai hammers that bass of his with way too many strings.&lt;/p&gt;
&lt;p&gt;As seems to be tradition, after the keyboard solo, Noro starts his mind bending minute long improvised solo. At 2:58 we also get a fun section where both Noro and Mukaiya plays these runs in perfect sync.&lt;/p&gt;
&lt;p&gt;The only respite from this absolutely high energy jam is ironically the drum solo around 3:23 where Sasaki gets to play in absolute silence from the rest of the band.&lt;/p&gt;
&lt;p&gt;Swallow is a banger that is filled to the brim with tiny little fills and riffs from every member of the band. Sasaki especially goes absolutely nuts on the drums for the whole duration of the track. For me, this is peak Casiopea.&lt;/p&gt;
&lt;h3 id=&quot;7-dream-hill&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#7-dream-hill&quot;&gt;7. Dream Hill&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Dream Hill is one of the slower tracks again. It’s also one of the rare tracks where we have vocals provided by Issei Noro. If you’re not allergic to cheesy early 80s’ Japanese music, you might find this track very bittersweet and beautiful.&lt;/p&gt;
&lt;p&gt;It’s a very fitting track before we transition into the last jam on the release.&lt;/p&gt;
&lt;h3 id=&quot;8-black-joke&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#8-black-joke&quot;&gt;8. Black Joke&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Again, a very iconic Casiopea track. It starts off with a very mysterious arpeggiating guitar that sets the mood perfectly as we transition into a more laidback beat with some funky call-and-response between the guitar and brass sections.&lt;/p&gt;
&lt;p&gt;If you’ve heard Casiopea’s Mint Jams album, this track definitely comes very close to the mood and sound of the Mint Jams songs. The whole mood of the track oscillates between mysterious and almost cheery, it keeps you guessing.&lt;/p&gt;
&lt;p&gt;Sakurai has some serious bass slaps in this track and I think the moving bassline during the verses sounds absolutely delightful.&lt;/p&gt;
&lt;p&gt;This song also hilights how well the band plays together, all the little breaks and flourishes when they all come together just works beautifully.&lt;/p&gt;
&lt;p&gt;Towards the end the intro motif repeats into what becomes the ending, a perfect ending for the album.&lt;/p&gt;
&lt;h2 id=&quot;final-conclusions&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/review/casiopeas-debut-album-review/#final-conclusions&quot;&gt;Final conclusions&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Casiopea’s debut album is funny in the sense that it’s not that reflective of where their sound will evolve to over the years but on the other hand, retrospectively you can absolutely see where they came from.&lt;/p&gt;
&lt;p&gt;The song writing and performance is simply stellar but the mixing is clearly very dated. I wouldn’t say that it’s bad but it’s also very obviously not a great mix either.&lt;/p&gt;
&lt;p&gt;I think as a whole it definitely stands the test of time and it’s also a very approachable album when it comes to fusion jazz music and that makes it an easy starting point to get into Casiopea’s discography. I might be biased, but I do strongly recommend checking the album out. Even if you’re not a fan of jazz, Casiopea is so much more than that!&lt;/p&gt;
&lt;p&gt;The album can be found on most streaming platforms these days. Happy listenings!&lt;/p&gt;
  &lt;section class=&quot;review-score&quot; style=&quot; background: var(--color-red,dark);&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;score&lt;/dt&gt; 
    &lt;dd&gt;95 / 100&lt;/dd&gt;
  &lt;/dl&gt;
  &lt;/section&gt;

    </content>
    <summary>Casiopea&#39;s titular album came out 45 years ago. Is it still any good?</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Summogon</title>
    <link href="https://httpster.io/project/summogon/" />
    <updated>2024-04-15T00:00:00Z</updated>
    <id>https://httpster.io/project/summogon/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/summogon/summogon-screenshot.webp&quot; alt=&quot;Screenshot from the game Summogon&quot; title=&quot;Screenshot from the game Summogon&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Summogon is the latest game me, Marko and Roni have worked on.&lt;/p&gt;
&lt;p&gt;It’s a dark and ominous card puzzle game that we made during last year’s Ludum Dare 55. It’s pretty short and can be played in less than 10 minutes, but most likely the puzzles will take a little while longer to figure out.&lt;/p&gt;
&lt;p&gt;To date, this is &lt;em&gt;easily&lt;/em&gt; the best ranked game we’ve made. Out of &lt;strong&gt;2194&lt;/strong&gt; games, Summogon had an overall rank of &lt;strong&gt;324th&lt;/strong&gt;, but our audio was ranked &lt;strong&gt;8th&lt;/strong&gt;! That means in terms of audio, we were in the top &lt;strong&gt;0.32%&lt;/strong&gt; which is absolutely insane.&lt;/p&gt;
&lt;p&gt;It was my first time writing any non-rhythmic music. The backing track has three different variations that loop depending on the progress in game, growing more sinister as the player gets towards the end.&lt;/p&gt;
&lt;p&gt;I recommend playing the game to really get in the mood of the soundscape, but if you’re impatient and just want to hear the music, the main track is also up on &lt;a href=&quot;https://soundcloud.com/httpsterio/summogon-theme-ld55&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;my SoundCloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Marko and Roni also made &lt;a href=&quot;https://ldjam.com/events/ludum-dare/54/flicker-of-lumina&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Flicker of Lumina&lt;/a&gt; between Summogon and Kantelemania, which is worth mentioning as it’s a very good game!&lt;/p&gt;

    </content>
    <summary>Sinister card game leaves players puzzled.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Webfonts and layout shifting</title>
    <link href="https://httpster.io/article/webfonts-and-layout-shifting/" />
    <updated>2024-01-29T00:00:00Z</updated>
    <id>https://httpster.io/article/webfonts-and-layout-shifting/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;In this article, I’ll outline why and how I matched my fallback font’s dimensions with my webfont’s settings to diminish the layout shifting.&lt;/p&gt;
&lt;p&gt;If you don’t want to read my ramblings, you should skip to the &lt;a href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#tl;dr&quot;&gt;TL;DR&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&quot;preamble&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#preamble&quot;&gt;Preamble&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In my quest for the coveted &lt;a href=&quot;https://www.11ty.dev/speedlify/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;“four-hundos”&lt;/a&gt;, aka. a perfect Lighthouse score, I’ve always ended up studying and fixing arcane issues I’ve never encountered before. This time around, I scored an abominable 95/100 for performance. The issue was the teeny-tiny amount of CLS, &lt;em&gt;cumulative layout shift&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In my case, the layout shift was caused by my webfont, &lt;em&gt;Vollkorn&lt;/em&gt;. When using webfonts, fonts that are not included in the user’s OS or device by default, you’ll encounter what’s called either &lt;strong&gt;FOUT&lt;/strong&gt; or &lt;strong&gt;FOIT&lt;/strong&gt; depending on how font-display is configured.&lt;/p&gt;
&lt;h2 id=&quot;fout-and-foit&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#fout-and-foit&quot;&gt;FOUT &amp;amp; FOIT&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;FOUT&lt;/strong&gt; stands for &lt;em&gt;Flash of Unstyled Text&lt;/em&gt; and &lt;strong&gt;FOIT&lt;/strong&gt; means &lt;em&gt;Flash of Invisible Text&lt;/em&gt;. So, either the user is briefly show the content in a fallback font the user has or the text will be entirely invisible until the webfont has loaded. Neither is ideal, but with &lt;em&gt;FOUT&lt;/em&gt;, the &lt;em&gt;time to interactive&lt;/em&gt; is shorter, which is always better.&lt;/p&gt;
&lt;p&gt;If neither temporarily unstyled or invisible text are viable options, the third option would be use font-display &lt;em&gt;&lt;strong&gt;optional&lt;/strong&gt;&lt;/em&gt;. This would mean that the browser will use the font only if the user already has the font when drawing the view. So, if the user has the font installed or cached, it’ll get used and otherwise it’ll just default to the fallback font. During the first page load, users will see the text in the fallback font and when they reload or navigate to another page on the site, the webfont will have downloaded and that will get used instead of the fallback.&lt;/p&gt;
&lt;p&gt;I’m not a fan of &lt;em&gt;optional&lt;/em&gt;, I would rather just use the &lt;a href=&quot;https://modernfontstacks.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;system font stack&lt;/a&gt; instead of having the first pageload in a completely different font from the rest of the pages.&lt;/p&gt;
&lt;h2 id=&quot;not-all-fonts-are-equal&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#not-all-fonts-are-equal&quot;&gt;Not all fonts are equal&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I had set &lt;em&gt;Vollkorn&lt;/em&gt; as the main body typeface and serif as the fallback with the font-display &lt;strong&gt;swap&lt;/strong&gt; option. It should default to &lt;em&gt;Times New Roman&lt;/em&gt; on most devices and after the browser has downloaded &lt;em&gt;Vollkorn&lt;/em&gt;, it’ll replace &lt;em&gt;Times New Roman&lt;/em&gt; with &lt;em&gt;Vollkorn&lt;/em&gt;. Users on my page would have a brief moment of &lt;em&gt;FOUT&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;My issue specifically stemmed from the fact that 16pt in one font doesn’t equal 16pt in another font. Space between letters and words in two fonts can be different, letters can have a different width as well as the ascenders and descenders can vary in size. A whole lot of variables.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/article/webfonts-and-layout-shifting/font%20overlap.webp&quot; alt=&quot;Vollkorn and Times New Roman fonts being compared on top of each other to illustrate their differences&quot; title=&quot;Vollkorn and Times New Roman fonts being compared on top of each other to illustrate their differences&quot; /&gt;
  &lt;figcaption&gt;Vollkorn in black and Times New Roman in red overlaid&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Before &lt;em&gt;Vollkorn&lt;/em&gt; is loaded and displayed, the page is laid out with &lt;em&gt;Times New Roman&lt;/em&gt; and they reserve a different amount of space on the screen. One font might occupy two lines whereas the other font could fit in just one. When swapping between the fonts, the content jumps.&lt;/p&gt;
&lt;p&gt;We need to &lt;em&gt;&lt;strong&gt;match our webfont and fallback font&lt;/strong&gt;&lt;/em&gt; so that they occupy roughly the same space on the page.&lt;/p&gt;
&lt;h2 id=&quot;the-solution&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#the-solution&quot;&gt;The solution&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After sifting through the &lt;a href=&quot;https://web.dev/articles/optimize-cls&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;web.dev&lt;/a&gt; articles on CLS, &lt;a href=&quot;https://adam.omg.lol/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Adam&lt;/a&gt; helpfully directed me to &lt;a href=&quot;https://www.smashingmagazine.com/2021/05/reduce-font-loading-impact-css-descriptors/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this article&lt;/a&gt; on Smashing Magazine by Barry Pollard. The article is more in-depth than anything I could ever write, it’s definitely worth a read!&lt;/p&gt;
&lt;p&gt;In the article, Barry links to two resources that eventually helped me solve my issues! The first one is &lt;a href=&quot;https://meowni.ca/font-style-matcher/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Font style matcher&lt;/a&gt; by Monica Dinculescu and &lt;a href=&quot;https://deploy-preview-15--upbeat-shirley-608546.netlify.app/perfect-ish-font-fallback/?font=Vollkorn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Automatic font matching&lt;/a&gt; by Malte Ubl.&lt;/p&gt;
&lt;p&gt;If the webfont in question is on Google Fonts, Malte’s tool will automatically give you a fallback font-face CSS rule with the &lt;em&gt;size-adjust&lt;/em&gt;, &lt;em&gt;ascent-override&lt;/em&gt; and fallback font set.&lt;/p&gt;
&lt;p&gt;In the case that the font isn’t available on Google Fonts, Monica’s tool comes in handy as it’s relatively easy to eyeball the dimensions with it.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/article/webfonts-and-layout-shifting/fontcomparison.webp&quot; alt=&quot;Vollkorn and Times New Roman fonts being compared side by side with corrections applied&quot; title=&quot;Vollkorn and Times New Roman fonts being compared side by side with corrections applied&quot; /&gt;
  &lt;figcaption&gt;Vollkorn on the left, Times New Roman with the corrections on the right&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;As illustrated in the picture above, it’s not perfect even with the corrections applied. We can see that the second paragraph isn’t perfectly aligned and with longer bouts of text, the content will still jump. It’s still infinitely better than the alternative of not matching the fonts.&lt;/p&gt;
&lt;p&gt;My font configuration looks roughly like this&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@font-face&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vollkorn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string url&quot;&gt;&quot;/fonts/vollkorn.woff2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400 900&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; swap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@font-face&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;serif-fallback&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;size-adjust&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 108.28%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;ascent-override&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 103%&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Times New Roman&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;token selector&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Vollkorn&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;serif-fallback&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With these fixes, we have a solid &lt;em&gt;&lt;strong&gt;100&lt;/strong&gt;&lt;/em&gt; for performance on Lighthouse!&lt;/p&gt;
&lt;h2 id=&quot;tl;dr&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#tl;dr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use &lt;a href=&quot;https://meowni.ca/font-style-matcher/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Font style matcher&lt;/a&gt; or &lt;a href=&quot;https://deploy-preview-15--upbeat-shirley-608546.netlify.app/perfect-ish-font-fallback/?font=Vollkorn&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Automatic font matching&lt;/a&gt; to match your fallback font’s sizing settings with your webfont. Create a font-face rule for the fallback with the settings applied and set your fallback font as an explicit fallback for your webfont.&lt;/p&gt;
&lt;h2 id=&quot;finishing-words&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/webfonts-and-layout-shifting/#finishing-words&quot;&gt;Finishing words&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Fonts are hard. You can always dig deeper and learn new things about them. At the same time, that’s also why it’s so rewarding to spend a day or two to squash out the bugs and squeeze out every last bit of performance. Earlier, I wrote an &lt;a href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;article on subsetting fonts&lt;/a&gt;, which I recommend checking out!&lt;/p&gt;
&lt;p&gt;If this post resonated with you or helped you out in any fashion, please tell me on Mastodon! Thank you so much for reading this far!&lt;/p&gt;

    </content>
    <summary>Solving shifting content with webfonts!</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Temporarily Abled</title>
    <link href="https://httpster.io/article/temporarily-abled/" />
    <updated>2024-01-04T00:00:00Z</updated>
    <id>https://httpster.io/article/temporarily-abled/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;Yesterday I was playing badminton with my friend. I won 4 out of 5 games. I might be fat, but overall I’m not in a terrible shape as I’ve been going to the gym and tried to work on my health lately.&lt;/p&gt;
&lt;p&gt;Today at about 17:10 I felt a jolt in my back.&lt;/p&gt;
&lt;p&gt;Despite my past background in sports, my recent-ish fitness craze and attempts at building a healthy lifestyle, I too am only &lt;em&gt;&lt;strong&gt;temporarily abled&lt;/strong&gt;&lt;/em&gt;. Today was a grim reminder of this.&lt;/p&gt;
&lt;p&gt;For about ten minutes, I tried to stretch my back. Slowly, my posture sank and I couldn’t stand up straight. I shouted for my wife, but she couldn’t hear me. I had to call her on my phone, despite her being in the next room. I couldn’t walk, I had to lean on the bed with both hands.&lt;/p&gt;
&lt;p&gt;For the next 20 minutes, we tried to get me into a chair, into the bed, on to the floor, anywhere really. I couldn’t move. Every tiny rotation on my spine felt like I being stabbed. For 20 minutes, I was stuck leaning on the bed.&lt;/p&gt;
&lt;p&gt;Yesterday, I was bouncing around the court, today I couldn’t sit without swearing and crying in pain. Eventually, after pushing through the pain, I managed to get in the chair. Sitting was painful as well, my spine compressed on itself and no position I was in gave any relief. The EMT’s arrived just after 18:05 and I got some temporary relief from a muscle relaxant shot.&lt;/p&gt;
&lt;p&gt;This isn’t the first time I’ve had issues with what appears to be sciatica, but it was definitely the first time I’ve been fully incapacitated by it. I’m only 32 years old, in my mind I’m still young. I exercise and &lt;em&gt;try&lt;/em&gt; to lead a healthy and active lifestyle. In reality I’m overweight, I smoke and I’m too sedentary.&lt;/p&gt;
&lt;p&gt;Depending on the statistics and definitions, roughly 1 in 4 lives with some type of disability. Unless you die an instant death in a freak accident, you will with a 100% certainty be disabled at some point in your life. I know it’s cheesy, but one shouldn’t take their health and a functioning body for granted.&lt;/p&gt;
&lt;p&gt;I’m not scared of death, but I am scared shitless of living in pain and disabled. Maybe the fear will ease as I get older, I do not know. For now, the only thing I can do, is to work harder on maintaining my health. When I do start showing my age and the eventual health issues start to creep up, I want to minimize any ill effects of my own doing.&lt;/p&gt;
&lt;p&gt;Currently my shitty lifestyle decisions outweighs the good decisions manyfold. Lifting heavy weights for a couple of hours a week doesn’t offset sitting at a desk for 14 hours a day, doing the occasional leg presses doesn’t compensate for never going on a jog.&lt;/p&gt;
&lt;p&gt;I don’t plan on ending up stuck with a bad back because I felt lazy or didn’t want to do something mildly uncomfortable. Fuck that.&lt;/p&gt;

    </content>
    <summary>I received a grim reminder today.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>In with the new, out with the old</title>
    <link href="https://httpster.io/article/in-with-the-new-out-with-the-old/" />
    <updated>2024-01-01T00:00:00Z</updated>
    <id>https://httpster.io/article/in-with-the-new-out-with-the-old/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;time-for-a-site-refresh&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/in-with-the-new-out-with-the-old/#time-for-a-site-refresh&quot;&gt;Time for a site refresh&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;After three and a half years exactly, I think it was time to rewrite my site. &lt;em&gt;I know, I know&lt;/em&gt;, it’s basically a meme at this point, webdevs rewriting their personal site and never updating it after that. But, my skills, needs and wants have changed over time and I felt like my site was keeping me from creating content and I felt it was justified in recreating it.&lt;/p&gt;
&lt;p&gt;This is a pretty long blog post, you’ve been warned!&lt;/p&gt;
&lt;h2 id=&quot;the-previous-site&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/in-with-the-new-out-with-the-old/#the-previous-site&quot;&gt;The previous site&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The previous version of this site had been based on a fork of Mike Riethmuller’s &lt;a href=&quot;https://github.com/MadeByMike/supermaya&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Supermaya&lt;/a&gt; Eleventy starter project. Eleventy was still pretty new at the time and there weren’t a ton of starter projects available. Supermaya kinda hit the sweet spot for me, being just enough fleshed out to get me going, but at the same it didn’t get too much in the way, which is why I originally picked it.&lt;/p&gt;
&lt;p&gt;Supermaya was by no means perfect. I found a handful of layout issues, some markup errors with regards to accessibility and even a few bugs related to images. That’s all to be expected. Supermaya also shipped with integrations for a CMS called KeystoneJS, which I effectively tore out. I also removed stuff related to inlining CSS above the fold as headless browsers don’t tend to play nicely with WSL and I wanted to simplify the site so that it’d be easier to get an actual understanding of how it all works. After a couple of days, I had my site up and running and over the next week, I kept optimizing and fixing things.&lt;/p&gt;
&lt;p&gt;After some point, Mike stopped supporting and updating the site and my pull requests didn’t get merged. As it’s FOSS, I have no expectations of the sorts anyways. I personally didn’t need anything from him either but as a starter template, I’d consider it archived and maybe not the best way forward. Eventually the site broke with the latest Node.js LTS version and upgrading it ended up really hacky. I did finally manage to migrate it to Eleventy 2.0 and Node.js 18, but after all my fixes and edits, the code started to be cumbersome to maintain.&lt;/p&gt;
&lt;p&gt;The biggest issue for me personally though was the fact that Mike has some very specific way of writing CSS layouts and I didn’t fully ever understand it. There was a lot of really elegant solutions and you could easily tell that Mike’s way of working was miles ahead of what I’m personally capable of. My code isn’t really maintainable or future proof as I’m kinda mixing two paradigms. So, I decided to start anew.&lt;/p&gt;
&lt;h2 id=&quot;experimentations&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/in-with-the-new-out-with-the-old/#experimentations&quot;&gt;Experimentations&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before rebuilding my site, I personally went through some life events. We got married with my wife just over a year ago and I needed to write up a photo gallery website for our wedding photos. I built the site from scratch with Eleventy and bash and made a starter project out of it, which is available &lt;a href=&quot;https://11ty-gallery.netlify.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here!&lt;/a&gt; This was actually a really fun and teaching project, although generating json with bash the way I did it is literally the silliest way and shouldn’t be replicated.&lt;/p&gt;
&lt;p&gt;I also needed to build a couple of other sites and found an Eleventy starter by Rong Ying, which I then forked into another starter project that can be found &lt;a href=&quot;https://11ty-blog-njk-starter.netlify.app/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;here&lt;/a&gt;. This was my first time experimenting with Tailwind and while I don’t love it, it does solve a lot of issues I had with creating layouts and I’ve opted to use it in my other projects since. I managed to find a handful of bugs in Rong Ying’s starter and I migrated the original project from Liquid to Nunjucks. I spent a good while on re-learning about templating, pagination and Liquid/NJK filters and functions.&lt;/p&gt;
&lt;h2 id=&quot;time-for-a-redo&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/in-with-the-new-out-with-the-old/#time-for-a-redo&quot;&gt;Time for a redo&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As I’ve said earlier, my previous websites had some issues that I wanted to avoid this time around. I’m under no illusion that this site would be the last one I’d ever make, but I would like for the content to be portable more easily and manageable for a longer while. I’m planning on generating, storing and displaying multiple kinds of data within one website and utilize this data in multiple ways.&lt;/p&gt;
&lt;p&gt;Things I’m trying to avoid are&lt;/p&gt;
&lt;ol class=&quot;list&quot;&gt;
&lt;li&gt;
&lt;p&gt;baking content and data into the markup code, these should be kept separate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;inheriting too much code I don’t fully understand myself.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Originally, I planned on writing my new site from scratch with Eleventy and Tailwind and stealing solutions from different templates and projects to solve each individual function. After too much mulling about and planning without actually doing anything, I came across Lene Saile’s &lt;a href=&quot;https://github.com/madrilene/eleventy-excellent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Eleventy Excellent&lt;/a&gt; starter project and just simply went with that as a base.&lt;/p&gt;
&lt;p&gt;Lene’s starter does a lot of very smart things, which at times make my life a lot easier and solve issues I couldn’t figure out myself and occasionally bites myself in the ass. After starting to work with the starter template I was contemplating a few times if I should abandon it and go with my original plan, but I decided to stick it out. And I’m glad I did.&lt;/p&gt;
&lt;p&gt;The starter project is very well structured and every feature and config is implemented in a way that’s quite easy to just replace or rip out entirely if I would choose to. Most of the &lt;em&gt;“black magic”&lt;/em&gt; isn’t done on the layout end of things and it comes with very little CSS so there isn’t any major paradigms I need to grok, so I feel this is a pretty safe base to start building on.&lt;/p&gt;
&lt;p&gt;As always, there’s a handful of bugs to fix, most of which are of my own making. I think that’s okay though. I’m not aiming for perfection and I don’t mind the site being published in a half-finished state as long as it’s usable. I’d rather just keep on occasionally working on it and at least have &lt;em&gt;something&lt;/em&gt; presentable released.&lt;/p&gt;
&lt;h2 id=&quot;for-the-future&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/in-with-the-new-out-with-the-old/#for-the-future&quot;&gt;For the future&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I don’t have a publicly documented laundry list of things I’ve planned for the site, I’m just going to go with the flow and work on whatever inspires me. I’m trying to track the evolution of the site on the &lt;a href=&quot;https://httpster.io/changelog/&quot;&gt;Changelog&lt;/a&gt; page. My main focus for now is simply to start writing more.&lt;/p&gt;
&lt;p&gt;Ideally, I’d get webmentions and comments integrated soon-ish, simply to encourage interaction and possibly garner some kind of readership. Despite working in marketing, I don’t really want to push my content though, that’s not within the &lt;em&gt;raison d’etre&lt;/em&gt; so I can’t say I’m too bothered. I would like to indiewebify my online presence a bit more, but it’s still a world I don’t fully understand. That’s the way forward though in my opinion.&lt;/p&gt;
&lt;p&gt;If you, dear reader, encounter some weird bugs or simply want to say ‘hi’, you should send me a message on Mastodon :) Have a great start of the year, cheers!&lt;/p&gt;

    </content>
    <summary>After three and a half years, it&#39;s time for a refresh.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Subset fonts with Python 3 and FontTools</title>
    <link href="https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/" />
    <updated>2023-05-09T00:00:00Z</updated>
    <id>https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;tl;dr&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#tl;dr&quot;&gt;TL;DR&lt;/a&gt;&lt;/h2&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;pip3 &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; fonttools brotli

pyftsubset YOURFONT.woff2 --output-file&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;YOURFONT-subset.woff2 --text-file&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;characters.txt &lt;span class=&quot;token parameter variable&quot;&gt;--flavor&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;woff2 --layout-features&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;kern&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;forewords&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#forewords&quot;&gt;Forewords&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I’m an avid fan of the static site generator Eleventy. In fact, this site was built with it &lt;em&gt;(and the lovely starter project Supermaya by &lt;a href=&quot;https://github.com/MadeByMike/supermaya&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Mike Riethmuller&lt;/a&gt;)&lt;/em&gt;. While trying to get my site to raise in the ranks on the &lt;a href=&quot;https://www.11ty.dev/speedlify/httpster-io/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Eleventy Leaderboards&lt;/a&gt;, I did my darnedest to optimize every aspect of the site. One of the things I did was to subset the fonts I use on the site. In this brief guide, I’ll share why and how I went about it.&lt;/p&gt;
&lt;h2 id=&quot;what-is-font-subsetting-and-why-should-i-care&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#what-is-font-subsetting-and-why-should-i-care&quot;&gt;What is font subsetting and why should I care?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Isn’t it just irritating when pages take ages to load? Even more annoying is when a page seems to have loaded but the proper fonts come in with a delay and the text jumps around. This is because the browser has to download the font files before it can render the text properly. Larger fonts take a longer time to download than a small font, even if the larger font is only used for a few characters.&lt;/p&gt;
&lt;p&gt;Subsetting a font means removing all of the extra symbols and characters from the font file that you don’t need and generating a new, subsetted font file with just the necessary characters. This new font file is much smaller than the original and will download faster. If you want to take people with slower internet speeds into consideration or you want to make your site more green, optimising your site’s overall data footprint is undoubtedly beneficial.&lt;/p&gt;
&lt;h2 id=&quot;what-are-my-options&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#what-are-my-options&quot;&gt;What are my options?&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There’s mainly two proper ways of subsetting a font. The first one would be to use an online tool like Font Squirrel’s &lt;a href=&quot;https://www.fontsquirrel.com/tools/webfont-generator&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Webfont Generator&lt;/a&gt;. It’s a brilliant tool, but it doesn’t support woff2 fonts, for instance, and doesn’t offer much additional assistance.&lt;/p&gt;
&lt;p&gt;Alternatively, you could use a command line tool such as &lt;a href=&quot;https://github.com/zachleat/glyphhanger&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Glyphhanger&lt;/a&gt; by Zach Leatherman or FontTools directly. Glyphhanger uses FontTools under the hood and provides some fun extra features like the ability to scan web pages for used characters and to gather all the used characters and symbols automatically.&lt;/p&gt;
&lt;p&gt;Glyphhanger is a great tool, but it’s a bit of a hassle to install and use. I’ve had some issues with it in the past, so I personally prefer to use FontTools directly. Glyphhanger uses a Chromium webdriver to scan web pages for used characters and I’ve had trouble with running webdriver based tools on WSL, hence me going the FontTools route. Less dependencies, less things to break.&lt;/p&gt;
&lt;p&gt;If you’re on MacOS and want to have a go with Glyphhanger, I can strongly recommend Sara Soueidan’s article &lt;a href=&quot;https://www.sarasoueidan.com/blog/glyphhanger/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;How I set up Glyphhanger on MacOS for optimizing and converting font files for the Web&lt;/a&gt;. It’s a great article even if you’re not a Mac user.&lt;/p&gt;
&lt;h2 id=&quot;im-sold!-lets-do-it!&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#im-sold!-lets-do-it!&quot;&gt;I’m sold! Let’s do it!&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You’ll need two things—A terminal emulator and Python3.&lt;/p&gt;
&lt;h3 id=&quot;1-make-sure-you-have-python3-installed&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#1-make-sure-you-have-python3-installed&quot;&gt;1. Make sure you have python3 installed&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you’re using a Mac or Linux, you can open your default terminal and type &lt;code&gt;which python3&lt;/code&gt; and if you see something like &lt;code&gt;/usr/bin/python3&lt;/code&gt; or similar, you’re good to go. If not, go and install it.&lt;/p&gt;
&lt;p&gt;If you’re on Windows, you’ll most likely need to install Python3. You can download it from &lt;a href=&quot;https://www.python.org/downloads/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;python.org&lt;/a&gt;. Make sure to check the box that says “Add Python 3.x to PATH” during the installation.&lt;/p&gt;
&lt;p&gt;Now, you’re ready to install FontTools.&lt;/p&gt;
&lt;h3 id=&quot;2-installing-fonttools-and-brotli&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#2-installing-fonttools-and-brotli&quot;&gt;2. Installing FontTools and Brotli&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can install FontTools by opening your terminal and typing &lt;code&gt;pip3 install fonttools brotli&lt;/code&gt;. If you get an error message, you might need to install &lt;code&gt;pip3&lt;/code&gt; or use &lt;code&gt;pip&lt;/code&gt; instead. If you’re on Windows, you might need to use &lt;code&gt;py -m pip install fonttools brotli&lt;/code&gt;. Brotli is required when processing woff2 files, FontTools will throw an error if you don’t have it installed.&lt;/p&gt;
&lt;p&gt;If you’re using Ubuntu on WSL, you might also have to install &lt;code&gt;pycryptodomex&lt;/code&gt;, &lt;code&gt;websockets&lt;/code&gt;, &lt;code&gt;mutagen&lt;/code&gt; and &lt;code&gt;zopfli&lt;/code&gt; with &lt;code&gt;pip3 install pycryptodomex websockets mutagen zopfli&lt;/code&gt;&lt;/p&gt;
&lt;h3 id=&quot;3-create-a-file-with-the-characters-you-want-to-keep&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#3-create-a-file-with-the-characters-you-want-to-keep&quot;&gt;3. Create a file with the characters you want to keep&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a basic &lt;code&gt;.txt&lt;/code&gt; file and inside the file, list all the characters you’re going to use on your website. My list of characters looks like this:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;1234567890!&quot;#%&amp;/()=?``´@£$€{[]}&#92;~^&#39;*-–—_.,:;&lt;&gt;|’½§qwertyuiopåasdfghjklöäzxcvbnmæøQWERTYUIOPÅASDFGHJKLÖÄZXCVBNMÆØéáíçñëèāÉÁÍÇÑËÈĀ&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Save the file as &lt;code&gt;characters.txt&lt;/code&gt; in the same folder as your font files.&lt;/p&gt;
&lt;p&gt;Notice, how you have to add both the lowercase and the uppercase variants of each letter. Any characters you don’t list here will be removed from the font file, so try to be as thorough as possible.&lt;/p&gt;
&lt;h3 id=&quot;4-figure-out-which-features-you-want-to-keep&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#4-figure-out-which-features-you-want-to-keep&quot;&gt;4. Figure out which features you want to keep&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Your font most likely comes with a kerning table, which is a table that tells the browser how much space to put between each character. Most fonts come with a bunch of other features you might or might not want to keep. I’m using Inter as an example and it comes with a whopping 35 OpenType features like symbols for cardinal numbers, fraction numbers etc. I don’t need any of those, but you might. So, it’s a good idea to check which options are available for your font. I personally prefer to use &lt;a href=&quot;https://fontdrop.info/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;FontDrop!&lt;/a&gt; to inspect the font before I start subsetting it.&lt;/p&gt;
&lt;p&gt;You can also use the command &lt;code&gt;pyftsubset YOURFONT.woff2 --layout-features=?&lt;/code&gt; to list all the available features.&lt;/p&gt;
&lt;p&gt;Make note of the features you want to keep and write them up somewhere. I’m going to keep only the kerning so I’m just going to write &lt;code&gt;kern&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;5-subset-the-font&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#5-subset-the-font&quot;&gt;5. Subset the font&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You have all the tools installed, your font in an woff2, otf or ttf format and a list of characters you want to keep. Now, it’s time to subset the font. Open your terminal and navigate to the folder where your font files are. Then, run the following command:&lt;/p&gt;
&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;pyftsubset YOURFONT.woff2 --output-file=YOURFONT-subset.woff2 --text-file=characters.txt --flavor=woff2 --layout-features=kern&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember to replace &lt;code&gt;YOURFONT&lt;/code&gt; with the actual name of the font you’re using and replace &lt;code&gt;kern&lt;/code&gt; with the features you want to keep. If you want to keep multiple features, separate them with a comma like this: &lt;code&gt;--layout-features=kern,liga&lt;/code&gt;. If you simply want to keep all of the layout features, you can also just type &lt;code&gt;--layout-features=*&lt;/code&gt; instead.&lt;/p&gt;
&lt;h2 id=&quot;afterwords&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/subset-fonts-with-python-3-and-fonttools/#afterwords&quot;&gt;Afterwords&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There you have it. Personally, I managed to reduce my font load from 472kb to 46kb, which reduced my frontpage’s loadsize by a whopping &lt;strong&gt;84.8%&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;If you want to learn more about FontTools, you can check out the &lt;a href=&quot;https://fonttools.readthedocs.io/en/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;official documentation&lt;/a&gt;. If you want to learn more about subsetting fonts, I can recommend &lt;a href=&quot;https://www.zachleat.com/web/subset-webfonts/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;this article&lt;/a&gt; by Zach Leatherman.&lt;/p&gt;
&lt;p&gt;Thanks for reading! If you enjoyed this tutorial, holler at me on Mastodon &lt;a href=&quot;https://social.lol/@sami&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;@sami@social.lol&lt;/a&gt; or you can shoot me an email firstname@websitename.&lt;/p&gt;
&lt;p&gt;Take care, stay happy and keep being brilliant!&lt;/p&gt;

    </content>
    <summary>Shrink your fonts and make your site faster.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Kantelemania</title>
    <link href="https://httpster.io/project/kantelemania/" />
    <updated>2023-02-05T00:00:00Z</updated>
    <id>https://httpster.io/project/kantelemania/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/kantelemania/kantelemania-screenshot.webp&quot; alt=&quot;Screenshot from the game Kantelemania&quot; title=&quot;Screenshot from the game Kantelemania&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After doing a few Ludum Dare games with the gang, we thought we’d try out Global Game Jam for a change.&lt;/p&gt;
&lt;p&gt;Having done &lt;a href=&quot;https://httpster.io/project/%5Bx-ed-out%5D/&quot;&gt;[X-ED OUT]&lt;/a&gt; earlier, we wanted to do another game that gets increasingly difficult with time and that’s basically a “play until you fail” type of survival game.&lt;/p&gt;
&lt;p&gt;We thought about the theme and diversifiers for a while, and came up with a Kalevala inspired rhythm game.&lt;/p&gt;
&lt;p&gt;The actual gameplay is very simple—hit the corresponding arrow or WASD key according to the arrows on the screen. Missing an arrow or pressing the wrong one will drop the hype meter. When the hype meter drops to zero, it’s game over.&lt;/p&gt;

    </content>
    <summary>Väinämöinen gets down with the funk.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>[X-ED OUT]</title>
    <link href="https://httpster.io/project/[x-ed-out]/" />
    <updated>2022-10-03T00:00:00Z</updated>
    <id>https://httpster.io/project/[x-ed-out]/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;[X-ED OUT] is the second Ludum Dare game we made with Marko and Roni. This time, my wife also joined us!&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/[x-ed-out]/x-ed-out-screenshot.webp&quot; alt=&quot;Screenshot from the game [X-ED OUT]&quot; title=&quot;Screenshot from the game [X-ED OUT]&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The game is quite simple. Turn around in your turret and aim at aliens. Clearing a wave of enemies lets you pick up XP from the ground, leveling up the turret. Rinse and repeat until defeat.&lt;/p&gt;
&lt;p&gt;We had a lot of fun making it and the game was also quite well received! Out of &lt;strong&gt;2420&lt;/strong&gt; games, we had an overall placement of &lt;strong&gt;185th&lt;/strong&gt;, fun was ranked &lt;strong&gt;73rd&lt;/strong&gt; and audio was &lt;strong&gt;68th&lt;/strong&gt;. It was the first time our gang had broken into the top 100 in any category.&lt;/p&gt;
&lt;p&gt;It’s really a quite fun game! Shoot some aliens and try to survive, I dare you!&lt;/p&gt;

    </content>
    <summary>Shooting aliens has never been more fun!</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Hello there</title>
    <link href="https://httpster.io/article/hello-there/" />
    <updated>2022-09-04T00:00:00Z</updated>
    <id>https://httpster.io/article/hello-there/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;So, I’m finally back after a break. As I have ADHD, I tend to drop things and hyperfocus on only certain aspects in my life. I’ve always been like this but it took me a long while to realize that it’s even happening.&lt;/p&gt;
&lt;p&gt;If our home needs cleaning (it always does), I might spend a few days just doing the laundry without touching any of our dishes. If our dishes needs doing, I’ll wash them over a couple of days but not take out the trash. The same pattern happens with almost everything I do and it’s not great really.&lt;/p&gt;
&lt;p&gt;For the past few weeks I’ve been bogged down with tiny tasks at work. Time-wise, they don’t amount to that much but just the mere existence of these tasks cause me the inability to further any other tasks in my life.&lt;/p&gt;
&lt;p&gt;We had our wedding last month, which means I haven’t really gotten much else done this whole past year haha. Apart from that, I’ve just enjoyed some quiet time, playing video games, making a tiny bit of music and working on some other smaller side projects. One of which is the wedding photos website, which I’m rather proud of actually!&lt;/p&gt;
&lt;p&gt;Now that I’m back in working mode, I’ll try to keep my head above the water and work on my website amongst other things and build that into more of a routine. Maybe it’ll help?&lt;/p&gt;
&lt;p&gt;Anyways, this was just a quick check-in. I’m still alive and well. Life is good as Vesku would always say.&lt;/p&gt;

    </content>
    <summary>Back from a hiatus, maybe?</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>New site, who dis?</title>
    <link href="https://httpster.io/article/new-site-who-dis/" />
    <updated>2020-06-07T00:00:00Z</updated>
    <id>https://httpster.io/article/new-site-who-dis/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;I’ve noticed during the past few years that I seem to follow a certain pattern. When I’m looking for work, I’ll set up a new personal website / online portfolio and work on it for a few weeks. Then I get hired, the site gets neglected and I always kinda wait for the inspiration to write more. &lt;em&gt;And nobody came&lt;/em&gt;.&lt;br /&gt;
During the last five-six years, I’ve abandoned at least the same amount of personal websites after the first few weeks and left them in various states of disarray.&lt;/p&gt;
&lt;p&gt;There has also been a lot of talk about how walled gardens and social media giants are rapidly killing off personal websites. Why go through the trouble to run a personal website, when you can have a personal Facebook page and promptly be dropped off by &lt;em&gt;&lt;strong&gt;the algorithm&lt;/strong&gt;&lt;/em&gt; faster than Google kills a product? Why don’t you post your articles on Medium and get them paywalled. How about posting your thoughts on Reddit or Twitter and get moderated or attacked by an angry mob to whom you cannot explain your inoffensive joke on a satisfactory level within the 280 character limit and get publicly lynched and ruined? Yeah, uh. It’s a shitshow these days.&lt;/p&gt;
&lt;p&gt;I’ve always agreed on some level that social media is most likely not very healthy for the human psyche and the way they also shape our societal cultures feels very unwelcome to me. Reddit and Twitter for example have been great breeding grounds for newly accepted publicly open racism as you can hide behind an anonymous moniker. Despite that, I’ve been on (and still am) on most commonly used social media platforms up until recently.&lt;/p&gt;
&lt;p&gt;I stopped using Reddit for a few years after finding it very toxic and a great waste of my time. Only just recently did I join back again and that’s only to moderate a music production subreddit that I’ve run with a few friends for some years, that’ll be the extent of my participation there. On Facebook on the other hand, I’ve only kept my account on the off-chance I need to get in touch with people I can’t message anywhere else.&lt;/p&gt;
&lt;p&gt;All of this dissatisfaction is amplified by the fact that, while I’m quite open and provide basically every detail of my life freely, I do not want my information to be used for some $BIG_CORP9000’s gain and profit. I don’t want to be spied on, as I hate the strategies the current online businesses and product startups have adopted as their path to profitability. Farming and selling user data to create extremely accurate predictive models of human behaviour. I hate the future these types of tools are indicative of.&lt;/p&gt;
&lt;p&gt;Then came Google with their AMP project. My personal and literal anti-Christ, were I a man of the cloth. Google wants to take all the good things about the internet, like decentralization, net neutrality, fair discovery and the possibility to create &lt;a href=&quot;https://www.kickscondor.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;crazy-ass personal&lt;/a&gt; websites? AMP was the last straw for me.&lt;/p&gt;
&lt;p&gt;As there has been a &lt;a href=&quot;https://news.ycombinator.com/item?id=23237559&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;few&lt;/a&gt; &lt;a href=&quot;https://news.ycombinator.com/item?id=23205588&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;threads&lt;/a&gt; on Hacker News about taking ownership of your own content, I finally decided to take the plunge and dedicate myself to write on my own site. Maybe there’s still hope with the rise of indie web mentality, the resurrection of RSS feeds and a general welcome of the good ol’ hacker ethos of showing a huge middle finger to everyone who tells us to get back in line.&lt;/p&gt;
&lt;p&gt;The past few years my social media usage has mostly been observing others and less about partaking in it myself. I feel that social media is very ephemeral in nature and doesn’t encourage longer write-ups that require more thought and deliver artefacts of great consideration and personal insight. My thoughts have more value, &lt;em&gt;at least to me&lt;/em&gt;, than a random small social commentary or joke doomed to be forever lost in the tides of time.&lt;/p&gt;
&lt;p&gt;I’ve set up a &lt;a href=&quot;https://httpster.io/feed.xml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;RSS Feed&lt;/a&gt; and welcome anyone to subscribe, if my innermost thoughts are of interest to you. This will be the dedicated central hub for creations, be it artistic or intrinsic in nature, of my personal handwork.&lt;/p&gt;
&lt;p&gt;I’ll open up on the technical aspects on how I’ve built this bastion of mine on a later date, you’ll just have to subscribe or check back on a later date if you want to read about it ;)&lt;/p&gt;

    </content>
    <summary>Taking back what&#39;s mine and sticking it to the man.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>CueBit</title>
    <link href="https://httpster.io/project/cuebit/" />
    <updated>2020-04-23T00:00:00Z</updated>
    <id>https://httpster.io/project/cuebit/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/cuebit/cuebit-screenshot.webp&quot; alt=&quot;Screenshot from the game CueBit&quot; title=&quot;Screenshot from the game CueBit&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;CueBit is my first solo game ever. I made it as the final project for my university programming project.&lt;/p&gt;
&lt;p&gt;It’s a simple pool game with some decent enough physics, custom sound design and retro graphics. It’s not the prettiest, most featureful pool game, but it works relatively well! It’s built with C# and a fork of MonoGame called Jypeli, maintained by the University of Jyväskylä.&lt;/p&gt;
&lt;p&gt;For the graphics —&lt;em&gt;they’re stunning, I know&lt;/em&gt;—I built &lt;a href=&quot;https://github.com/aseprite/aseprite&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Aseprite&lt;/a&gt; from the source code and the audio was made with my trusty copy of FL Studio.&lt;/p&gt;
&lt;p&gt;Building it for Windows in this day and age was a bit of a chore, but I got it up and running. I managed to port it to the latest .Net runtime and latest version of Jypeli. I also added some quality of life updates to the messaging system. The comments and code is mainly in Finnish so it might not be the clearest project, but I’ll try to translate it, it’s only about 800 LOC in total.&lt;/p&gt;
&lt;p&gt;Anyways, feel free to grab the release from the GitHub down below and give the game a go!&lt;/p&gt;

    </content>
    <summary>A simple pool game made for university.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>I, Love, Robot</title>
    <link href="https://httpster.io/project/i-love-robot/" />
    <updated>2018-04-23T00:00:00Z</updated>
    <id>https://httpster.io/project/i-love-robot/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/i-love-robot/robot%20screenshot.webp&quot; alt=&quot;Screenshot from the game I, Love, Robot&quot; title=&quot;Screenshot from the game I, Love, Robot&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I, Love, Robot was the first of many games I got to make with my old friend Marko and his university classmate Roni.&lt;/p&gt;
&lt;p&gt;This game is all about helping robots date. You, as a system administrator, have to figure out which kind of messages each robot is partial to and zap any unseemly dad jokes or boring anecdotes about sports etc.&lt;/p&gt;
&lt;p&gt;It’s a fun little game jam game, You can play it in the browser even!&lt;/p&gt;

    </content>
    <summary>Robot Dating Simulator Duck Hunting Game made for Ludum Dare 41!</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Embracing music genres</title>
    <link href="https://httpster.io/article/embracing-music-genres/" />
    <updated>2015-06-22T00:00:00Z</updated>
    <id>https://httpster.io/article/embracing-music-genres/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;Lately, I’ve seen so many rants about “why do you need to categorize music” and “genres don’t matter”. And to be honest, you don’t need to, and they don’t matter.&lt;/p&gt;
&lt;p&gt;But they help. And I’ll tell you why.&lt;/p&gt;
&lt;p&gt;Have you ever heard a song that is simply amazing, unlike anything you’ve experienced before? It resonates with you, and you just have to keep listening to it on repeat. Wouldn’t it be incredible to find more music that excites you in the same way? I know I’d appreciate it.&lt;/p&gt;
&lt;p&gt;Here’s where it gets tricky. People often see genres as a way to pigeonhole songs into separate bins. They try to assign each song to a specific genre, while in reality, it doesn’t work that way. The way I see it, all songs take influences from various styles and tracks. Unless you’re the creator of something entirely new that sets the benchmark for a wholly new genre, you most likely combined a few genres and created some fusion music that may or may not be original.&lt;/p&gt;
&lt;p&gt;Genres should be treated as labels. Combine the labels, and you get a genre that might represent the style. Instead of saying,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“No, this isn’t psytrance; this is twilight,”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;you might say,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Yeah, I think this psytrance has some strong night psy and full-on influences, so I guess this falls under twilight.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I personally find this useful when trying to describe music to other people. Especially in the creative business, being able to use your words to recreate an experience from another medium is crucial. You can’t usually sell work just on its merits; you need to explain why it’s exceptional. If you can’t, you don’t understand it well enough yourself.&lt;/p&gt;
&lt;p&gt;The two biggest problems I see with genres are that they evolve and get misused. Genre names get misused partly because the definition of a genre might change over time, and people try to ride the mainstream bandwagon, misusing the genres on purpose.&lt;/p&gt;
&lt;p&gt;Take Beatport’s House category, for example. Half of the tunes in the top list aren’t even close to house as a genre. Instead, they use it as a catch-all term for anything with a 4x4 beat. If I were to look for music that genuinely falls under the house category, like Jacking House, Disco House, or French House, I’d most likely find zero tracks. However, if I wanted big room EDM-influenced tracks or some future music with a 4x4 beat, that would be labeled as house.&lt;/p&gt;
&lt;p&gt;This is just one example of misuse. The same happens for techno—a genre you’ve probably heard a billion times. But have you ever actually heard a real techno tune? No, DJ Mangoo’s Eurodancer doesn’t count. This misunderstanding is partially because people who look at genres from the outside don’t know enough about the styles to assess them appropriately. It’s similar to when your mom calls all game consoles Nintendos, right?&lt;/p&gt;
&lt;p&gt;Another issue with categorization is how styles evolve. Deep house ten years ago meant something &lt;em&gt;&lt;strong&gt;entirely&lt;/strong&gt;&lt;/em&gt; different from what it means today. That’s because people heard “house” (aka big room stuff) and, when they created more relaxed and melodic tracks with deeper basslines, labeled it as deep house. They used their previously false knowledge to create new false genres, which furthered the confusion.&lt;/p&gt;
&lt;p&gt;It doesn’t help that this mostly happens in more mainstream genres, causing the false names to gain momentum and the adoption of these genre names to become more popular. Thus, it never stops.&lt;/p&gt;
&lt;p&gt;This doesn’t mean that genres are inherently bad. We should use them as tags, and analyze the music we like, trying to pinpoint what separates and connects them. This helps us explore and discover new and exciting music, while making conversations about music and its various styles more descriptive and meaningful. Embracing genres as a tool for understanding and communication can open up a world of possibilities for music lovers everywhere.&lt;/p&gt;

    </content>
    <summary>Understanding the usefulness of music genres for discovery and communication.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Don&#39;t waste your money on preground coffee</title>
    <link href="https://httpster.io/article/dont-waste-your-money-on-preground-coffee/" />
    <updated>2015-06-09T00:00:00Z</updated>
    <id>https://httpster.io/article/dont-waste-your-money-on-preground-coffee/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;OK. Coffee is pretty popular here in Finland. It’s actually so popular that Finland is ranked either as the first or second in terms of coffee consumption per capita depending on which stats you look at.&lt;/p&gt;
&lt;p&gt;We drink coffee, we depend on it. And as always these days, hipsters want to resurrect everything that is a niche or different. Beer microbreweries, vinyl records and beards, you name it. The same happened to coffee. We’ve seen a great spurt of new independent microroasteries appearing left and right, roasting expensive speciality coffee.&lt;/p&gt;
&lt;p&gt;And that’s great! It means I don’t have to go out on my way to get a good cup of joe around here these days. But there are some people who don’t understand the concept of quality coffee. People who take their Pumpkin Spice with a dozen pumps of syrup or people who pre-grind their coffee at the store.&lt;/p&gt;
&lt;p&gt;I think it’s perfectly acceptable to buy the “regular” coffee from the grocery store, pay some 8€ per kilogram or so and enjoy that. I do that too. Hell, I’d go broke if I’d only drink speciality coffee. I’m not an eliltist, if you enjoy your coffee, it’s good coffee.&lt;/p&gt;
&lt;p&gt;But what I DON’T get, are people who buy speciality coffee for a premium price (40€/kg or more) and grind it in the store. Ok, if you plan on cycling home in 10 minutes and prepare all the coffee you just bought at once, it’d be okay. But if you end up with beans you grinded more than half an hour ago, you fucked up.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;‘But it was just roasted yesterday’&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No, you fucked up. I would rather drink coffee that was roasted a year ago but grinded just before brewing than letting my freshly roasted beans get stale. Why would you pay 5x the price for coffee you’re gonna let go bad? Stick with your Keurig or capsule coffees, you’ll get your moneys worth.&lt;/p&gt;
&lt;p&gt;Less is lost with whole roasted beans than grinded beans. The difference is huge. I can easily drink a cup that was roasted several months ago and stored in an airtight jar and say that it’s delicious. Not so much for that super expensive Geisha pregrounded coffee that costed an arm and a leg.&lt;/p&gt;
&lt;p&gt;If you truly want to enjoy good coffee at home, you NEED to invest in a grinder. No, your smoothie blender isn’t good enough nor is that crappy piece of an excuse coffee grinder with metal blades. Get any burr grinder, like the Hario Minimill you can snatch for $22. It’ll beat your $100 electric grinder any day.&lt;/p&gt;
&lt;p&gt;If you’re not grinding your expensive beans yourself just before brewing, you’re either dumb, under false assumption that it’s okay or just generally okay with throwing your money in /dev/null. Stop it.&lt;/p&gt;

    </content>
    <summary>Only silly people buy preground special coffee. Here&#39;s why.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Fastest MEAN stack install on Ubuntu</title>
    <link href="https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/" />
    <updated>2015-06-07T00:00:00Z</updated>
    <id>https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;h2 id=&quot;fastest-mean-stack-install-on-ubuntu&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/#fastest-mean-stack-install-on-ubuntu&quot;&gt;Fastest MEAN Stack Install on Ubuntu&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This article is from 11 years ago, so it’s likely not to work or be the recommended method of achieving the desired end result.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you’re looking for a server stack that’s more JavaScript-friendly than your everyday LAMP stack, MEAN (MongoDB, Express.js, AngularJS, and Node.js) is a great option to consider. This stack is mostly written in JS and integrates nicely with modern JavaScript tools like Grunt, making it a natural choice for web developers who want to bring the backend closer to the frontend.&lt;/p&gt;
&lt;p&gt;The best part? Installing MEAN is surprisingly easy, even for command line noobs like me. Here’s how to set it up in just a few minutes.&lt;/p&gt;
&lt;h3 id=&quot;step-1-create-your-project-directory-and-download-nodejs&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/#step-1-create-your-project-directory-and-download-nodejs&quot;&gt;Step 1: Create your project directory and download Node.js.&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;First, you’ll need to create a directory for your project. You can do this by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; myproject &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; myproject&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, you need to download Node.js and npm. You can do this by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-fsSL&lt;/span&gt; https://deb.nodesource.com/setup_20.x &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-E&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;bash&lt;/span&gt; - &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&#92;&lt;/span&gt;
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt; nodejs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nodesource’s Node is more up to speed than the default package from &lt;code&gt;apt-get&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Node.js is used to run JavaScript on the serverside, while npm is the package manager for Node.js applications, scripts, and tools. To install the necessary dependencies locally to the project, you can create a &lt;code&gt;package.json&lt;/code&gt; file by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; init &lt;span class=&quot;token parameter variable&quot;&gt;-y&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will create a &lt;code&gt;package.json&lt;/code&gt; file in the project directory with some default values. You can then install the required packages by running the following command:&lt;/p&gt;
&lt;h3 id=&quot;step-2-install-mongodb&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/#step-2-install-mongodb&quot;&gt;Step 2: Install MongoDB&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next, you’ll need to install MongoDB, which is the database for your project. You can do this by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; mongodb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;MongoDB is a NoSQL database, which means it handles certain tasks better than other databases, like MySQL. Depending on the project, you might want to swap this out for some other DB system. One nice feature of MongoDB is that the database files are formatted pretty much like JSON, which can be handy.&lt;/p&gt;
&lt;h3 id=&quot;step-3-install-yeoman&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/#step-3-install-yeoman&quot;&gt;Step 3: Install Yeoman&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You’ll need Yeoman to generate your project. Yeoman is a scaffolding tool that helps you get started with new projects by generating boilerplate code, installing dependencies, and more. You can download Yeoman through npm by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; yo&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The “-g” flag is for a global install of the tool. Once you’ve installed Yeoman, you can install the MEAN.JS generator by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-g&lt;/span&gt; generator-meanjs&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;step-4-generate-your-project&quot;&gt;&lt;a class=&quot;heading-anchor&quot; href=&quot;https://httpster.io/article/fastest-mean-stack-install-on-ubuntu/#step-4-generate-your-project&quot;&gt;Step 4: Generate Your Project&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that you have all the necessary tools installed, you can generate your MEAN.JS project by running the following command:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;yo meanjs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Yeoman generator will ask you a few questions about your app. Fill in the info (or just hit enter), and once the installer is done, run the following command to start your MEAN server:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;grunt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that’s it! Your brand new MEAN server should now be visible on either &lt;code&gt;http://localhost:3000&lt;/code&gt; or &lt;code&gt;http://YOUR-IP:3000&lt;/code&gt;. Enjoy!&lt;/p&gt;

    </content>
    <summary>I&#39;ll show you how to set up a MEAN stack in just a few minutes.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Stranded in Jyväskylä</title>
    <link href="https://httpster.io/project/stranded-in-jyvaskyla/" />
    <updated>2015-02-26T00:00:00Z</updated>
    <id>https://httpster.io/project/stranded-in-jyvaskyla/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/stranded-in-jyvaskyla/stranded-screenshot.webp&quot; alt=&quot;Screenshot from the game Stranded in Jyväskylä&quot; title=&quot;Screenshot from the game Stranded in Jyväskylä&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Stranded in Jyväskylä is a point-and-click set in the city of Jyväskylä, Finland.&lt;/p&gt;
&lt;p&gt;We made this during the 2015 Global Game Jam and I’ll be the first to admit that it was a disaster.&lt;/p&gt;
&lt;p&gt;There’s roughly five minutes of gameplay in total and it’s not very engaging. I only worked on the music so I can’t really say anything other than we didn’t really know what kinda game we were doing and all of the time just went into… something?&lt;/p&gt;
&lt;p&gt;The game is up on Github if you’re so inclined. I wouldn’t be.&lt;/p&gt;

    </content>
    <summary>Game Jam gone awry... :c</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Parallax</title>
    <link href="https://httpster.io/project/parallax/" />
    <updated>2015-02-18T00:00:00Z</updated>
    <id>https://httpster.io/project/parallax/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;During my studies at the university of applied sciences, I completed an elective minor in video game production worth 19 ECTS study credits or roughly 500 hours. A majority of the time was spent working as teams producing a game.&lt;/p&gt;
&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/parallax/paradogs-logo.webp&quot; alt=&quot;Paradogs logo featuring a german shepheard dog with a parachute&quot; title=&quot;Paradogs logo featuring a german shepheard dog with a parachute&quot; /&gt;
  &lt;figcaption&gt;Paradogs logo featuring a snazzy doggo with a parachute&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Our team was called Paradogs and the game is called Parallax. The Paradogs team consisted of two programmers, a graphics artist, a game designer and myself. I was in charge of project management, communications, sound design and music.&lt;/p&gt;
&lt;p&gt;We had a website, marketing material and some cool email addresses like sami@parado.gs&lt;/p&gt;
&lt;figure&gt;
  &lt;video width=&quot;640&quot; preload=&quot;auto&quot; muted=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot;&gt;
    &lt;source src=&quot;https://httpster.io/assets/images/projects/paradogs/paradogs-outer.webm&quot; type=&quot;video/webm&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;The intro features some bleak cityscapes&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Parallax is a platformer game with a creatively stylized main character &lt;em&gt;(a white box)&lt;/em&gt; that you have to navigate through a myriad of traps and precision requiring rooms. Although there isn’t a whole ton of content, we’re very proud of this little demo we made.&lt;/p&gt;
&lt;p&gt;There’s a short gameplay &lt;a href=&quot;https://www.youtube.com/watch?v=X47C7yVymHM&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;video up on YouTube&lt;/a&gt; showing a bit of the first level.&lt;/p&gt;
&lt;p&gt;We spent the last night before ending the course building our whole presentation inside the actual game. Instead of doing a boring old PowerPoint post-mortem of the project, we had an interactive presentation/game hybrid. No sleeps were had, but it was worth it as we scored full marks with our game.&lt;/p&gt;
&lt;p&gt;I just recently dug up the source code and lo and behold, it still compiles with Unity 4.7.2! So, I put the &lt;a href=&quot;https://github.com/httpsterio/Paradogs&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;code up on GitHub&lt;/a&gt; with a Windows build as well.&lt;/p&gt;
&lt;p&gt;If you do happen to check it out, I’d love to hear what you think of it!&lt;/p&gt;

    </content>
    <summary>MVP demo of a simple platformer game with tight controls and physics. Made as the final project for my minor in video games.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Snakes etc. On A Plain</title>
    <link href="https://httpster.io/project/snakes-etc-on-a-plain/" />
    <updated>2014-01-24T00:00:00Z</updated>
    <id>https://httpster.io/project/snakes-etc-on-a-plain/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/snakes-etc-on-a-plain/snakes-screenshot.webp&quot; alt=&quot;Screenshot from the game Snakes etc. On A Plain&quot; title=&quot;Screenshot from the game Snakes etc. On A Plain&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Snakes etc. On A Plain is the second game jam game I’ve been a part of building and it’s also possibly one of the most fun ones!&lt;/p&gt;
&lt;p&gt;The game is a local co-op platformer where each player controls an animal character while being able to swap which animal the other player is playing. Each animal has a different movement mechanic and all of them are required to clear different parts of the levels.&lt;/p&gt;
&lt;p&gt;The game is fun, fast paced and chaotic.&lt;/p&gt;
&lt;p&gt;It’s built with Python 2.7, pyglet 1.2 and py2exe. I also set up a Github action that can build a Windows executable on each tagged release. Mac and Linux builds should be fairly straightforward to build, I included some of the Python libraries in the Git repo so you can use pip to install them.&lt;/p&gt;

    </content>
    <summary>Local co-op platformer that gets a bit hectic.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Pandan Puuhapeli</title>
    <link href="https://httpster.io/project/pandan-puuhapeli/" />
    <updated>2013-04-24T00:00:00Z</updated>
    <id>https://httpster.io/project/pandan-puuhapeli/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;figure&gt;
  &lt;img src=&quot;https://httpster.io/project/pandan-puuhapeli/panda%20screenshot.webp&quot; alt=&quot;Screenshot from Panda&#39;s activity game&quot; title=&quot;Screenshot from Panda&#39;s activity game&quot; /&gt;
  &lt;figcaption&gt;Screenshot from the game&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Pandan Puuhapeli (Panda’s activity game) was the second year group project I did during my studies at the University of applied sciences.&lt;/p&gt;
&lt;p&gt;The game’s audience is roughly first graders (7 ish years of age) and it consists of a series of educational mini games. It’s made with Flash and ActionScript 2.&lt;/p&gt;
&lt;p&gt;For a long time after finishing the project, I wasn’t really happy with the end result. The team worked quite well together, but we struggled to come up with any good ideas to go on. The idea of an educational game for kids was kinda a safe option that nobody really felt that passionate about.&lt;/p&gt;
&lt;p&gt;12 years later—&lt;em&gt;has it really been that long?&lt;/em&gt;—, I’m actually quite proud of it. It’s a solid game that actually looks and sounds better than a lot of actually publicly funded edutainment games made around that time. I could definitely see the game being played on some iPad in a dentist’s waiting room.&lt;/p&gt;
&lt;p&gt;The game is entirely in Finnish, I don’t recommend it unless you’re somewhat fluent in the language. It also needs &lt;a href=&quot;https://www.newgrounds.com/flash/player&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Newgrounds’ flash emulator&lt;/a&gt; or something similar, Ruffle.rs doesn’t emulate it properly.&lt;/p&gt;

    </content>
    <summary>A Flash based edutainment game for kids.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry>  <entry>
    <title>Student Life Simulator</title>
    <link href="https://httpster.io/project/student-life-simulator/" />
    <updated>2013-02-19T00:00:00Z</updated>
    <id>https://httpster.io/project/student-life-simulator/</id>
    <content
      xml:lang=""
      type="html"
      >&lt;p&gt;We made Student Life Simulator during my first game jam ever, way back in 2013.&lt;/p&gt;
&lt;p&gt;I didn’t know anybody there and had next to zero gamedev experience, but I’d already worked with music and audio for a few years so I got teamed up with some people needing a sound and game designer.&lt;/p&gt;
&lt;p&gt;After some brainstorming and sketching the first evening, we had a solid idea locked in and started working. The end result was chaotic. In a good way.&lt;/p&gt;
&lt;figure&gt;
  &lt;video width=&quot;640&quot; preload=&quot;auto&quot; muted=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot;&gt;
    &lt;source src=&quot;https://httpster.io/assets/images/projects/studentlife/student-life-gameplay.webm&quot; type=&quot;video/webm&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;Can you keep up with the hectic student life?&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The goal of Student Life Simulator is to not die. Simple enough, just keep your heart rate under 200 and you’re golden.&lt;/p&gt;
&lt;p&gt;Oh and don’t forget to cook food, take out the trash, do the dishes, fill out benefit applications, answer the door and keep yourself intoxicated enough to not hate life. Failing at any of these tasks will raise your heart rate faster than eating a metric ton of salmiakki will.&lt;/p&gt;
&lt;p&gt;In short, you have to play six simultaneous minigames for as long as possible. It’s quite fun! The code and release version is up on GitHub!&lt;/p&gt;

    </content>
    <summary>An utterly silly, chaotic game jam game.</summary>
    <author>
      <name>Sami Mäkelä</name>
    </author>
  </entry></feed>
