<?xml version="1.0" encoding="utf-8" ?>

<rss version="2.0"
     xmlns:atom="http://www.w3.org/2005/Atom"
     xmlns:content="http://purl.org/rss/1.0/modules/content/"
     xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
    <title>Christofer Sandin — Texts</title>
    <link>https://christofersandin.com/texts</link>
    <atom:link href="https://christofersandin.com/feed.xml" rel="self" type="application/rss+xml" />
    <description>Texts by Christofer Sandin — essays, mini-essays and terminal treats about working in the digital world.</description>
    <language>en</language>
    <generator>Statamic</generator>
    
    <lastBuildDate>Fri, 15 May 2026 22:00:00 +0000</lastBuildDate>
    
    
    <item>
        <title>The Invisible Art of Typography</title>
        <link>https://christofersandin.com/texts/the-invisible-art-of-typography</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/the-invisible-art-of-typography</guid>
        <pubDate>Fri, 15 May 2026 22:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Article</category>
        
        <description>There are many books and articles on typography, but I think many still fail to take full advantage of all the features available to create great type on the web. To illustrate how much difference good typography makes, I’ve put together a little demo site where you can toggle the crafted…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>There are many books and articles on typography, but I think many still fail to take full advantage of all the features available to create great type on the web.</strong></p>
</div>
<p>To illustrate how much difference good typography makes, I’ve put together a little demo site where you can toggle the <strong>crafted typography</strong> on and off, along with the <em>OpenType</em> features that control how typefaces display specific things like lining numbers, small caps, and stylistic effects.</p>
<p>You can also simulate slow loading and ensure that the fallback fonts are as close as possible to the final experience to minimize cumulative layout shifts (CLS) and content jumping during load.</p>
<p><strong>Take a look at <a href="https://christofersandin.com/typography/">christofersandin.com/typography</a> – toggle things on and off and see if you can both see and feel the difference.</strong></p>
<p><em>Please note, the article itself is quite informative and includes a few great resources. But it’s not written by me — rather, it’s generated from the typography articles I’ve collected over many years, since the main point of this exercise was to display great typography, not the article content itself.</em></p>
<hr />
<h2>Resources</h2>
<p><strong>Craft and OpenType features</strong></p>
<ul>
<li><a href="https://practicaltypography.com/">Butterick’s Practical Typography</a> by Matthew Butterick</li>
<li><a href="http://webtypography.net/">The Elements of Typographic Style Applied to the Web</a> by Richard Rutter</li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_fonts/OpenType_fonts_guide">OpenType font features guide</a> by MDN</li>
<li><a href="https://sparanoid.com/lab/opentype-features/">The Complete CSS Demo for OpenType Features</a></li>
<li><a href="http://practice.typekit.com/lesson/caring-about-opentype-features">Caring about OpenType features</a> by Typekit Practice</li>
<li><a href="https://youtu.be/TreBK-EyACQ">Problems solved by OpenType</a> by Roel Nieskens, CSS Day 2024</li>
<li><a href="https://sinja.io/blog/get-maximum-out-of-your-font">Features of your font you had no idea about</a> by OlegWock</li>
<li><a href="https://alistapart.com/article/web-typography-tables/">Web Typography: Designing Tables to be Read, Not Looked At</a> by Richard Rutter, <cite>A List Apart</cite></li>
<li><a href="https://clagnut.com/blog/2433">Introducing TODS – a typographic and OpenType default stylesheet</a> by Richard Rutter</li>
<li><a href="https://wakamaifondue.com/">Wakamai Fondue</a> – see which features a font actually supports</li>
</ul>
<p><strong>Font loading and fallbacks</strong></p>
<ul>
<li><a href="https://developer.chrome.com/blog/font-fallbacks">Improved font fallbacks</a> by Katie Hempenius, Chrome Developers</li>
<li><a href="https://screenspan.net/fallback">Fallback Font Generator</a> by Brian Louis Ramirez</li>
<li><a href="https://seek-oss.github.io/capsize/">Capsize</a> – metric-matched fallbacks and predictable text sizing</li>
<li><a href="https://web.dev/blog/font-size-adjust">CSS font-size-adjust is now in Baseline</a> by web.dev</li>
<li><a href="https://modernfontstacks.com/">Modern Font Stacks</a></li>
<li><a href="https://scottjehl.com/posts/async-fonts-foit/">Fast &amp; Smooth Third-Party Web Fonts</a> by Scott Jehl</li>
<li><a href="https://www.debugbear.com/blog/website-font-performance">The Ultimate Guide to Font Performance Optimization</a> by DebugBear</li>
<li><a href="https://iamvdo.me/en/blog/css-font-metrics-line-height-and-vertical-align">Deep dive CSS: font metrics, line-height and vertical-align</a> by Vincent De Oliveira</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: npm</title>
        <link>https://christofersandin.com/texts/npm</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/npm</guid>
        <pubDate>Mon, 11 May 2026 22:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>Working in the terminal with web development, you’ll likely be running into Node and the Node Package Manager (npm) sooner or later. It&#039;s a standardized way to install and use JavaScript-based software — here&#039;s a summary of some useful commands. Packages can be installed globally or per project.…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>Working in the terminal with web development, you’ll likely be running into Node and the Node Package Manager (npm) sooner or later. It&#8217;s a standardized way to install and use JavaScript-based software — here&#8217;s a summary of some useful commands.</strong></p>
</div>
<p>Packages can be installed globally or per project.</p>
<h2>Global packages</h2>
<ul>
<li>
<p>List all globally installed packages<br />
<code>npm list -g --depth=0</code></p>
</li>
<li>
<p>You can check for a particular module installed globally. This is particularly useful when checking what version of a module you are using globally (remove the <code>-g</code> flag if checking a local module):<br />
<code>npm list -g --depth=0 | grep &lt;module_name&gt;</code></p>
</li>
</ul>
<h2>Packages</h2>
<ul>
<li>
<p>If you&#8217;d like to see all available (remote) versions for a particular module, then do:<br />
<code>npm view &lt;module_name&gt; versions</code>.<br />
Note that <em>versions</em> is in the plural. This will give you a complete listing of versions to choose from.</p>
</li>
<li>
<p>For the latest remote version:<br />
<code>npm view &lt;module_name&gt; version</code>  <br />
Note that the <em>version</em> is singular.</p>
</li>
<li>
<p>To find out which packages need to be updated, you can use<br />
<code>npm outdated -g --depth=0</code></p>
</li>
<li>
<p>To update global packages, you can use<br />
<code>npm install -g &lt;package&gt;</code></p>
</li>
<li>
<p>To update all global packages, you can use:<br />
<code>npm update -g</code></p>
</li>
</ul>
<p>Another way would be to use <code>npm-check-updates</code> (or <code>ncu</code> for short).</p>
<h2>References</h2>
<ul>
<li><a href="https://nodejs.org/">Node</a></li>
<li><a href="https://www.npmjs.com/">npm</a></li>
<li><a href="https://www.npmjs.com/package/npm-check-updates">npm-check-updates</a></li>
<li><a href="https://docs.npmjs.com/cli/v11/commands/npm-outdated/">npm-outdated</a> in the official npm Docs</li>
<li><a href="https://docs.npmjs.com/updating-packages-downloaded-from-the-registry/">Updating packages downloaded from the registry</a> in the official npm Docs</li>
<li><a href="https://devhints.io/npm">npm cheatsheet</a> by devhints.io</li>
<li><a href="http://www.tomsquest.com/blog/2018/10/better-npm-ing">Better NPM’ing, Tips and Tricks using NPM</a> by Tom’s Quest</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Embrace a Little Boredom</title>
        <link>https://christofersandin.com/texts/embrace-a-little-boredom</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/embrace-a-little-boredom</guid>
        <pubDate>Mon, 11 May 2026 22:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Article</category>
        
        <description>When people in Sweden wait for the bus or tram, I&#039;d guess 95% of them pick up their phone and start looking at it if there&#039;s more than 30 seconds of waiting time. I don&#039;t think that is healthy. This has really caught my attention over the past few years. It may be because I can&#039;t look at my phone…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>When people in Sweden wait for the bus or tram, I&#8217;d guess 95% of them pick up their phone and start looking at it if there&#8217;s more than 30 seconds of waiting time. I don&#8217;t think that is healthy.</strong></p>
</div>
<p>This has really caught my attention over the past few years. It may be because I can&#8217;t look at my phone or read while traveling by bus or train due to motion sickness, or it may be something else, but it&#8217;s almost comical looking at a bus stop in Sweden today. Twenty-three grown-ups are waiting, and everybody is staring down at a small screen, not talking to each other, not aware of what&#8217;s happening around them. Twenty-three little isolated islands are being &quot;socially connected&quot; without any social connection.</p>
<p>These constant stimuli and dopamine injections have sent us down a very slippery slope, and I&#8217;m not sure we&#8217;ll get to the bottom without falling.</p>
<h2>How we got here</h2>
<p>I remember watching videos from Asia 10-15 years ago of people riding the subway, where everybody was looking at their phones. We laughed and said, &quot;What a weird way to spend your day. It&#8217;s unsociable and lonely despite being among hundreds of others in a small space. How could anybody want to travel like that for hours in a commute back and forth every day?&quot;</p>
<p>Now, 15 years later, we&#8217;re there—probably even worse.</p>
<h2>The value of boredom</h2>
<p>I&#8217;ve recently read several books and listened to talks about the value of embracing boredom and resisting the urge for that quick fix of information or dopamine hit whenever we have to wait — in line, for the bus, for our food to be prepared.</p>
<p>But is there value in actually being bored from time to time, or is it just a matter of maximizing your time every day and trying to squeeze in as much information or entertainment as possible?</p>
<p>I&#8217;m uneasy about how we use our phones, especially the countless hours people spend on social media, browsing 5-10 second clips one after the other—constant stimulus for our brains.</p>
<p>I have two kids, and I try to keep them away from that kind of exposure as much as I can. But I&#8217;m actually worried that in a few years a significant portion of the country&#8217;s population will struggle to focus for more than 15 seconds.</p>
<h2>Ignoring the research</h2>
<p>Despite the overwhelming evidence from schools, classroom situations, research, and literature that we are heading in the wrong direction, we do little to address the issue.</p>
<p>My wife is a teacher, and she sees a dramatic difference today compared with 15 years ago.</p>
<p>This fixation on constant updates and stimuli in our nervous system makes us more anxious, unhappy, and unable to concentrate. It also introduces a strange fear of any boredom that lasts more than a few seconds. How did we end up here, and why aren&#8217;t we doing anything about it?</p>
<p>Let&#8217;s get back to giving the brain a little cognitive pause every now and then. I&#8217;ve also heard it suggested that it is in these pauses that we tend to process and sort information. So, let&#8217;s embrace a little boredom now and again. Just like you need to pause between runs when doing interval training — you need that part to make the runs better and to improve the result of the session.</p>
<h2>A major problem</h2>
<p>While we&#8217;re on the subject of running: this constant stimulus, combined with a severe lack of physical activity, results in a major problem. Strangely, we don&#8217;t prioritize this more, and I&#8217;m afraid we will see severe consequences in a few years.</p>
<p>When I see mothers and fathers sticking screens in front of their one-year-olds instead of talking to them or interacting with them — so they can be on their own phones while walking in the park — I&#8217;m appalled, and I lose a little bit of faith in humanity.</p>
<p>We are supposed to be educated and enlightened and should be able to do better! So, the next time you&#8217;re waiting for the bus, try keeping your hands in your pockets for two minutes and embrace the boredom.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://youtu.be/Ky6HHgiNGfU?si=hTXug7O19myZ_Oi8">What Boredom Teaches You</a> by Robert Greene</li>
<li><a href="https://hbr.org/2025/08/you-need-to-be-bored-heres-why">You Need to Be Bored. Here&#8217;s Why.</a> by Harvard Business Review and Dr. Arthur Brooks</li>
<li><cite><a href="https://calnewport.com/writing/">Digital Minimalism</a></cite> by Cal Newport</li>
<li><cite><a href="https://calnewport.com/writing/">Slow Productivity</a></cite> by Cal Newport</li>
<li><cite><a href="https://www.hubermanlab.com/podcast">Huberman Lab</a></cite> podcast by Andrew Huberman</li>
<li><a href="https://iontelligence.substack.com/p/issue-62-embracing-cognitive-solitude">Embracing “Cognitive Solitude” Is The Key To Thriving In The Age of AI</a> by Ion Valis</li>
<li><cite><a href="https://www.anxiousgeneration.com/book">The Anxious Generation</a></cite> by Jonathan Haidt</li>
<li><a href="https://journals.sagepub.com/doi/10.1177/0956797612446024">Inspired by Distraction: Mind Wandering Facilitates Creative Incubation</a> by Baird, Smallwood, et al.</li>
<li><a href="https://www.ted.com/talks/manoush_zomorodi_how_boredom_can_lead_to_your_most_brilliant_ideas">How boredom can lead to your most brilliant ideas</a> by Manoush Zomorodi, TED</li>
<li><a href="https://www.apa.org/news/podcasts/speaking-of-psychology/attention-spans">Why our attention spans are shrinking</a> with Gloria Mark, <cite>Speaking of Psychology</cite></li>
<li><cite><a href="https://www.amazon.com/gp/aw/d/0306832011">Wherever You Go, There You Are</a></cite> by Jon Kabat-Zinn</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Connecting Figma, Fractal and Craft CMS with Claude Code</title>
        <link>https://christofersandin.com/texts/connecting-figma-fractal-and-craft-cms-with-claude-code</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/connecting-figma-fractal-and-craft-cms-with-claude-code</guid>
        <pubDate>Tue, 17 Feb 2026 23:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Work</category>
        
        <description>Yesterday, an updated version of the Figma MCP server for Claude Code was released. The big news was that you could now go from code to Figma, as well as the other way around. While watching the Winter Olympics on TV, I set up a little project to try this out. I was curious if this was just another…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>Yesterday, an updated version of the <em>Figma MCP</em> server for <em>Claude Code</em> was released. The big news was that you could now go from code to <em>Figma</em>, as well as the other way around.</strong></p>
</div>  
<p>While watching the Winter Olympics on TV, I set up a little project to try this out. I was curious if this was just another toy, or actually something useful for professional work. Going back and forth between Figma and code has been a real pain — until now?</p>
<p>To put this to the test I came up with the following idea in the first power break:</p>
<ol>
<li>Use Claude Code to fetch a website.</li>
<li>When captured, push the designs into a Figma document (both desktop and mobile versions of each page).</li>
<li>Use Claude Code to analyze the Figma document and designs and create the different content blocks in <em>Fractal</em> with HTML, CSS, and JavaScript according to my specifications.</li>
<li>Install <em>Craft CMS</em>.</li>
<li>Let Claude Code implement the static blocks in Fractal into dynamic versions in Craft and add the necessary fields and settings.</li>
<li>Then have Claude Code create all the relevant pages and build the content with the created blocks.</li>
</ol>
<p>For the test I used:</p>
<ul>
<li><a href="https://www.figma.com/">Figma</a></li>
<li><a href="https://fractal.build/">Fractal</a> and <a href="https://craftcms.com/">Craft CMS</a> (both running on <a href="https://ddev.com/">DDEV</a>)</li>
<li><a href="https://github.com/anthropics/claude-code">Claude Code</a></li>
</ul>
<p>And the following three MCP servers:</p>
<ul>
<li><a href="https://github.com/ChromeDevTools/chrome-devtools-mcp">Chrome DevTools MCP</a></li>
<li><a href="https://github.com/figma/mcp-server-guide">Figma MCP</a></li>
<li><a href="https://github.com/stimmtdigital/craft-mcp">Craft CMS MCP</a></li>
</ul>
<p>I&#8217;m on the Claude Code Max plan running Opus 4.6 when writing this and the Figma document, consisting of about 20 page designs, took about two hours to fetch. The blocks and elements took about another 45 minutes. And after getting the Craft MCP server to play nice, the complete build took another hour or so.</p>
<p>The results are not perfect, but still fantastic. The build quality is absolutely good enough that letting the AI produce a starting point is worth a lot.</p>
<p>During the process I did have to go in and &quot;project manage&quot; Claude to do the right things, so it was not a case of just telling the agent to &quot;build this site&quot; right away. Reading the proposed plans, writing up and specifying the setup took another hour or two but, all in all, the process was way better than I had imagined.</p>
<p>To be fair, I had extensive instructions on how to build both the blocks and the elements in Fractal as well as thorough instructions on how I wanted the CSS to be written. This way I can guide the agent to write this the same way that I would have done it on my own - just way faster.</p>
<p>Since we&#8217;re not using <em>React</em> or <em>Tailwind CSS</em> at Republic, it was very important that the code generated from Figma was written according to our specs and not in the standard &quot;Tailwind and React way&quot;, which AI seems to have been trained on for the most part.</p>
<p>I was also very clear about the fact that I wanted Claude Code to <strong>use the Craft MCP server for creating things instead of creating YAML files</strong>. The YAML files are the files representing the database schema in Craft but should be generated by the system, not by an error-prone LLM. Generating YAML files directly might be another way to go, but a single error in one of them makes the whole process choke, so I liked the approach where Craft generates those files after the MCP commands are executed instead.</p>
<p>The best thing is that I had my colleague go into Figma, tweak the design there, and then tell Claude to update the current block in Fractal according to the new design in Figma. That worked like a charm and it was rather <strong>nice to see his actual design and the decisions he made show up in code without me having to implement it</strong>.</p>
<p>This is the first time we have an actual setup that lets us go back and forth between code and Figma, without major hassle. For a first try, I think this went really well.</p>
<p>Getting a lot of the grunt work done by AI frees up valuable time. This means that we can focus more time on the things we humans are best equipped to do: solving the clients&#8217; problems and doing the creative work needed for a really good user experience. The fun and interesting things.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://help.figma.com/hc/en-us/articles/32132100833559-Guide-to-the-Dev-Mode-MCP-Server">Guide to the Figma MCP server</a> by Figma</li>
<li><a href="https://developer.chrome.com/blog/chrome-devtools-mcp">Chrome DevTools MCP</a> by Chrome for Developers</li>
<li><a href="https://code.claude.com/docs/en/best-practices">Claude Code best practices</a> by Anthropic</li>
<li><a href="https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/">Spec-driven development with AI: get started with a new open source toolkit</a> by GitHub</li>
<li><a href="https://github.com/github/spec-kit">Spec Kit</a> and <a href="https://github.com/Fission-AI/OpenSpec/">OpenSpec</a> – spec-driven development toolkits for AI coding assistants</li>
<li><a href="https://substack.com/home/post/p-184990361">How to write a good spec for AI agents</a></li>
<li><a href="https://addyo.substack.com/p/my-llm-coding-workflow-going-into">My LLM coding workflow going into 2026</a> by Addy Osmani</li>
<li><a href="https://substack.com/home/post/p-185933546">The 80% Problem in Agentic Coding</a></li>
<li><a href="https://github.com/ben-rogerson/craft-storybook-starter">craft-storybook-starter</a> – a living style guide with Twig components for Craft CMS</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Using AI Based on Your Curated Sources Is an Excellent Use of Technology</title>
        <link>https://christofersandin.com/texts/using-ai-based-on-your-curated-sources</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/using-ai-based-on-your-curated-sources</guid>
        <pubDate>Sat, 09 Aug 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Article</category>
        
        <description>There are so many mentions of AI in technology and software today that you can hardly do anything without having to opt out or opt in to some AI feature in every application you open, no matter what the purpose of the application is. I&#039;m one of the people who have a hard time with AI being slapped…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>There are so many mentions of AI in technology and software today that you can hardly do anything without having to opt out or opt in to some AI feature in every application you open, no matter what the purpose of the application is.</strong></p>
</div>
<p>I&#8217;m one of the people who have a hard time with AI being slapped onto everything, as if that automatically made the application better than before. In certain situations, AI can be of excellent service, especially in doing mundane tasks that are easily described, but there are a lot of places where AI does not add anything substantial at all, except marketing jargon.</p>
<p>At the same time, the <a href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Models</a> (LLMs) are continuously improving, and can be a great help in processing information and helping us organize it.</p>
<p>During the summer, I spent some time trying out AI-powered services to educate myself and explore cutting-edge technology. But using AI for research and to help you build things is not as easy as you might think. If you want to develop good-quality solutions, the <em>hallucination effects</em> (when AI presents false information confidently) of AI agents can be devastating to your research, and the &quot;good enough&quot; outdated technical answers can also bite you if you&#8217;re not careful and good at assessing the responses.</p>
<p>It&#8217;s a thin rope to walk.</p>
<p>Since AI today more or less makes up things and presents them as facts without being the least bit embarrassed, we need to start checking the source material and not just assume that AI always knows. Going down this route made me take a look at <em>NotebookLM</em> from Google since it is one of the services that give you references to the data it confidently presents.</p>
<h2>NotebookLM</h2>
<p><a href="https://notebooklm.google/">NotebookLM</a> is a service where you can add multiple sources in the form of PDFs, Markdown, and text. But also links and YouTube videos, as well as Google Docs and Sheets.</p>
<p>When done adding sources, you let Google&#8217;s <em>Gemini</em> 2.5 AI process the material, and then you can chat and ask questions, create an audio podcast where two AI hosts discuss your preferred topic, create a presentation, and get access to a mind-map-like outline of the subject, as well as FAQs and Study questions.</p>
<p>You can also get the results in 50 different languages, so even a small language like Swedish is supported. I understand that it&#8217;s easier than before thanks to AI, but it&#8217;s still nice to see Google include minor languages like that.</p>
<p>The option to interrupt and ask questions while listening to the audio playback is an elegant feature. Like calling into a discussion on the radio and having the hosts target the discussion around your question.</p>
<p>Since it&#8217;s a &quot;free&quot; Google product, you can&#8217;t be sure it will be around in a year or two, but trying it out right now is fun. Give it a bunch of source material that you know is good and that you like to work with, sit back, and then enjoy the audio discussion based on this.</p>
<h2>An Obsidian MCP server</h2>
<p>Another thing that piqued my interest was the ability to install local MCP servers. The <a href="https://modelcontextprotocol.io/overview">Model Context Protocol</a>, or MCP for short, is a way to connect AI agents to sources other than the LLM they already use.</p>
<p>This made it possible to hook up an AI application like <a href="https://claude.ai/download">Claude Desktop</a> to <a href="https://obsidian.md">Obsidian</a>. Obsidian is the app where I do and store most of my writing today, and the content is saved in Markdown format.</p>
<p>With the MCP server in place, I was able to add my texts written about various subjects, book recommendations, and research to Claude Desktop and have that material accessible in the AI-based chat context.</p>
<p>That made it possible to ask questions like:</p>
<ul>
<li>&quot;Based on all the books listed in the &#8216;Books&#8217; folder, could you recommend five other titles that you think I&#8217;d like to read?&quot;</li>
<li>&quot;Look up the ISBNs and the official websites (if they exist) and add them as properties to the books in Obsidian.&quot;</li>
<li>&quot;Create a reading list by finding all book mentions across my notes and organizing them by topic.&quot;</li>
</ul>
<h2>GitHub Copilot in Zed and Neovim</h2>
<p>At work, we use <a href="https://www.jetbrains.com/phpstorm/">PhpStorm</a> from JetBrains. Even though I&#8217;m not writing code every day anymore due to other responsibilities, I still do from time to time. Therefore, I&#8217;m not as heavily invested in the IDEs and editors as ten years ago, but I think the AI Assistant in PhpStorm is rather good, and I&#8217;ve used it in a few situations. (They also have a new, updated AI coding agent called <a href="https://www.jetbrains.com/junie/">Junie</a>, which I haven&#8217;t tried yet.)</p>
<p>But I wanted to explore using AI in an editor like <a href="https://neovim.io/">Neovim</a>, where I had to dig a little deeper before getting it to work. I installed the Neovim <a href="https://github.com/zbirenbaum/copilot.lua">copilot.lua</a> and <a href="https://github.com/CopilotC-Nvim/CopilotChat.nvim">Copilot Chat</a> plugins and gave them a try. I have to admit that while it worked well enough, the experience was not up to par with the one in PhpStorm (probably because of my somewhat moderate Neovim skills), but that made me try the same thing in <a href="https://zed.dev/">Zed</a>.</p>
<p>And I&#8217;ve got to say, Zed might be a sweet spot when it comes to being able to use the Vim motions that I&#8217;m starting to be accustomed to when editing code, as well as giving me a high-speed editor and a GUI for the things where this makes sense.</p>
<p>(<em>Vim motions</em> refer to keyboard shortcuts that let you move around and edit text efficiently without reaching for the mouse.)</p>
<p>So, what would you have AI help you out with when you have it in the editor?</p>
<p>If you exclude the option to have the AI generate actual code for you from scratch, which, in my experience, seldom ends up exactly the way you want it, you can use the AI as a colleague.</p>
<ul>
<li>Ask <em>Copilot</em> to explain complex code patterns you encounter.</li>
<li>Request refactoring suggestions for improving code maintainability.</li>
<li>Ask for performance optimization suggestions and reviews.</li>
</ul>
<p>And a final one I haven&#8217;t used yet but see potential in: having it write commit messages that accurately describe changes.</p>
<p>The main thing is to make sure that the AI agent has access to the whole project and your code base so that it can provide appropriate advice. Context, again, is significant for making the AI helpful rather than adding confusion and complexity.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://notebooklm.google/">NotebookLM</a> by Google</li>
<li><a href="https://www.youtube.com/watch?v=FOs4RDTC52Q">The Ultimate Guide to NotebookLM</a> by <a href="https://www.youtube.com/@TeachersTech">Teacher&#8217;s Tech</a></li>
<li><a href="https://www.forbes.com/sites/quickerbettertech/2024/11/27/why-googles-notebooklm-is-a-killer-app-for-small-business/">Why Google’s NotebookLM Is A Great App For Small Business</a> by Gene Marks, <cite>Forbes</cite></li>
<li><a href="https://www.anthropic.com/claude">Claude AI</a> by Anthropic</li>
<li><a href="https://www.youtube.com/watch?v=VeTnndXyJQI">Let Claude Automate Your Obsidian Notes: Second Brain AI Agent (MCP)</a> by <a href="https://www.youtube.com/@zenvanriel">Zen van Riel</a></li>
<li><a href="https://github.com/features/copilot">GitHub Copilot</a></li>
<li><a href="https://simonwillison.net/2023/Oct/23/embeddings/">Embeddings: What they are and why they matter</a> by Simon Willison</li>
<li><a href="https://www.anthropic.com/news/contextual-retrieval">Introducing Contextual Retrieval</a> by Anthropic</li>
<li><a href="https://arxiv.org/abs/2005.11401">Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks</a> – the original RAG paper</li>
<li><a href="https://www.docling.ai/">Docling</a> – open-source document processing for AI</li>
<li><a href="https://github.com/unclecode/crawl4ai">crawl4ai</a> – an LLM-friendly web crawler</li>
<li><a href="https://daverupert.com/2025/05/notion-to-obsidian/">Moving from Notion to Obsidian</a> by Dave Rupert</li>
<li><a href="https://tylersticka.com/journal/obsidian-miscellany/">Obsidian Miscellany</a> by Tyler Sticka</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: Lazygit</title>
        <link>https://christofersandin.com/texts/terminal-lazygit</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-lazygit</guid>
        <pubDate>Fri, 25 Jul 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>Lazygit is a Git TUI for the text-based world and a solid alternative to the Git Tower application for macOS I&#039;ve been using for years. It takes a little while to get around in Lazygit, but all in all, the shortcuts make sense after some time. The trickiest thing to get used to, in my opinion, is…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong><em>Lazygit</em> is a Git <abbr title="Terminal User Interface">TUI</abbr> for the text-based world and a solid alternative to the <a href="https://www.git-tower.com/mac">Git Tower application</a> for macOS I&#8217;ve been using for years.</strong></p>
</div>
<p>It takes a little while to get around in <a href="https://github.com/jesseduffield/lazygit">Lazygit</a>, but all in all, the shortcuts make sense after some time. The trickiest thing to get used to, in my opinion, is that you move left and right to go from section to section, but visually, they are placed underneath each other.</p>
<p>You use up and down to navigate each section, so in that regard, it makes sense to use left and right to move between them, but it feels weird pressing right and seeing the section under the current section light up.</p>
<p>Otherwise, you use</p>
<ul>
<li><code>Space</code> to stage and unstage files,</li>
<li><code>c</code> to commit,</li>
<li><code>d</code> to discard,</li>
<li><code>s</code> to stash, etc.,</li>
</ul>
<p>so many of the other shortcuts are pretty intuitive.</p>
<p><code>P</code> for push and <code>p</code> for pull also take some time to commit to muscle memory.</p>
<p>You always have a few of the most common shortcuts for the current situation in the bottom row on the screen, and you can always press the <code>?</code> to get a list of all the commands.</p>
<p>Combined with <a href="https://github.com/dandavison/delta">Delta</a> and a side-by-side config, diffs look good too.</p>
<h2>Resources</h2>
<ul>
<li><a href="https://github.com/jesseduffield/lazygit">Lazygit</a></li>
<li><a href="https://github.com/dandavison/delta">Delta</a></li>
<li>Introduction called <cite><a href="https://www.youtube.com/watch?v=VDXvbHZYeKY">Save Time With Lazygit</a></cite> by the creator Jesse Duffield</li>
<li><a href="https://jesseduffield.com/15-Lazygit-Features/">15 Lazygit Features In 15 Minutes</a> by Jesse Duffield</li>
<li><a href="https://jesseduffield.com/Lazygit-5-Years-On/">Lazygit Turns 5: Musings on Git, TUIs, and Open Source</a> by Jesse Duffield</li>
<li><a href="https://dandavison.github.io/delta/">Delta user manual</a> – the pager configuration behind the side-by-side diffs</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>The Non-Algorithmic Internet</title>
        <link>https://christofersandin.com/texts/the-non-algorithmic-internet</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/the-non-algorithmic-internet</guid>
        <pubDate>Sun, 08 Jun 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Personal</category>
        
        <description>I listened to Cal Newport&#039;s podcast the other day. His producer, Jessie, and he discussed &quot;the algorithm,&quot; which encourages us to use sites whose sole purpose is to keep us spending as much time as possible on them. The biggest problem is algorithm-based social media. Its purpose is to…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>I listened to <a href="https://www.thedeeplife.com/listen">Cal Newport&#8217;s podcast</a> the other day. His producer, Jessie, and he discussed &quot;the algorithm,&quot; which encourages us to use sites whose sole purpose is to keep us spending as much time as possible on them.</strong></p>
</div>
<p>The biggest problem is algorithm-based social media. Its purpose is to narrow our chain of thought, show us content from people who say what we like to hear, and indoctrinate us more and more, making us waste time looking at ads.</p>
<p>Nothing more, nothing less.</p>
<p>What to do? The answer is to spend time curating your resources, reading what interesting people have to say, listening to good music, listening to podcasts that interest you, and interacting with the personal web.</p>
<div style="text-align: center; margin: 1lh 0;">*</div>
<p>Along the same lines, Dan Sinker argues that we should not lean into mediocre AI-generated content in his well-researched and thoughtful article &quot;<a href="https://dansinker.com/posts/2025-05-23-who-cares/">The Who Cares Era</a>&quot;.</p>
<blockquote>
<p>In a moment where machines churn out mediocrity, make something yourself. Make it imperfect. Make it rough. Just make it.</p>
</blockquote>
<p>That resonates with me. If the art of creating and thinking is reduced to writing a prompt that asks an AI to summarize the most common thoughts about a subject, we will struggle to invent new ideas and think creative thoughts.</p>
<p>AI can help us, but thinking and originality are not criteria we can put on these large language models. They are a large set of data — texts and ideas other people have already thought of — and they are unable to think on their own.</p>
<p>Dan&#8217;s conclusion: as &quot;the culture of the Who Cares Era grinds towards the lowest common denominator,&quot; we should &quot;support those that are making real things.&quot; And he continues, &quot;Listen to something with your full attention. Watch something with your phone in the other room. Read an actual paper magazine or a book.&quot;</p>
<div style="text-align: center; margin: 1lh 0;">*</div>
<p>For me, that was purchasing and reading the book <cite><a href="https://www.niggli.ch/produkt/grid-systems-in-graphic-design/">Grid Systems in Graphic Design</a></cite>, written by Josef Müller-Brockmann, last week. This book made me rethink the way I create grids in CSS, which I can use in my profession, and induced creativity that I wouldn&#8217;t have had otherwise.</p>
<p>I understand that a book about grid systems from 1981 may not be something for everyone, but find your own subject and delve into it.</p>
<p><em><strong>The Internet can be a lovely place, made by humans for other humans.</strong></em></p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://neustadt.fr/essays/the-small-web/">Rediscovering the Small Web</a> by Parimal Satyal</li>
<li><a href="https://matthiasott.com/articles/into-the-personal-website-verse">Into the Personal-Website-Verse</a> by Matthias Ott</li>
<li><a href="https://maggieappleton.com/garden-history">A Brief History &amp; Ethos of the Digital Garden</a> by Maggie Appleton</li>
<li><cite><a href="https://www.penguinrandomhouse.com/books/695902/filterworld-by-kyle-chayka/">Filterworld: How Algorithms Flattened Culture</a></cite> by Kyle Chayka</li>
<li><a href="https://darekkay.com/blog/rss-styling/">Style your RSS feed</a> by Darek Kay</li>
<li><a href="https://slashpages.net/">slash pages</a> – personal-web convention pages like /now, /uses, and /blogroll</li>
<li><a href="https://ultrasciencelabs.com/lab-notes/why-we-are-still-using-88x31-buttons">Why we are still using 88x31 buttons</a> by Ultra Science Labs</li>
<li><a href="https://esif.dev/">Educational Sensational Inspirational Foundational</a> – a curated canon of web writing</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Writing a Mini-Essay</title>
        <link>https://christofersandin.com/texts/writing-a-mini-essay</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/writing-a-mini-essay</guid>
        <pubDate>Sun, 18 May 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Mini-essay</category>
        
        <description>I like to write. Research, writing, and editing help me understand a new subject. In my line of work — technology — you need to keep learning. For the last month, I have been using mini-essays, short essays about a single topic: one idea, one page. Let&#039;s see how they work in practice. In short,…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>I like to write. Research, writing, and editing help me understand a new subject. In my line of work — technology — you need to keep learning. For the last month, I have been using <em>mini-essays</em>, short essays about a single topic: one idea, one page. Let&#8217;s see how they work in practice.</strong></p>
</div>
<p>In short, when you find something interesting, you do the research and then write a mini-essay about the subject. Aim for 100-300 words.</p>
<p>A mini-essay — a format that has gained popularity lately — is one way to learn more about a specific subject. The format reminds me of the essay structure taught to us in school, and should follow the same three-part shape:</p>
<ul>
<li>Intro</li>
<li>Body</li>
<li>Conclusion</li>
</ul>
<p><strong>The intro should be clear and tell the reader about the subject.</strong> But you must also be interesting and make the reader want to continue. It could be a bold statement, three sentences that inspire emotion, or a question.</p>
<p>Using the mini-essay format when exploring a subject has benefits.</p>
<p><strong>Writing about something makes you understand it</strong>. Writing down your thoughts and ideas demands a greater understanding of the subject than talking about it. This is referred to as the <a href="https://en.wikipedia.org/wiki/Generation_effect">Generation effect</a>.</p>
<p>There is also the <a href="https://www.csinow.edu/career-tips/the-feynman-technique-the-best-learning-method-youve-never-heard-of-before/">Feynman technique</a> – <strong>teaching something to learn it</strong> – a tried and tested method for understanding things. It&#8217;s named after the Nobel Prize-winning physicist Richard Feynman, and the main idea is that if you can explain it to others, you usually have a good understanding of the subject.</p>
<p>A mini-essay will also force you to be precise since you only have 100-300 words to play with.</p>
<p><em>I find the mini-essay format inspiring. I see two significant benefits: I&#8217;m forced to keep it short, and since it&#8217;s not an in-depth article, the barrier to publishing is lower.</em></p>
<hr />
<h2>References</h2>
<ul>
<li><a href="https://youtube.com/watch?v=N4YjXJVzoZY&amp;si=lhaTvxkt3DUPhhOE">Mini Essays: The Ultimate Learning Tool</a></li>
<li><a href="https://youtube.com/watch?v=eCaOSNxwCsw&amp;si=wZWJX6ZC2P8V6PCW">How to Write a Mini-Essay</a></li>
<li><a href="https://youtube.com/watch?v=XsIK2kVbH6Y&amp;si=IWLLyxyvYYuXA22t">How to Write Mini Essays (in Obsidian)</a></li>
<li><a href="https://www.wired.com/2011/01/learning-methods/">To Learn Best, Write an Essay</a></li>
<li><a href="https://www.grammarly.com/blog/academic-writing/short-essay/">How to Write a Short Essay, With Examples</a></li>
<li><a href="https://notes.andymatuschak.org/Evergreen_notes_should_be_atomic">Evergreen notes should be atomic</a> by Andy Matuschak</li>
<li><a href="https://zettelkasten.de/atomicity/">The Principle of Atomicity</a> by Zettelkasten Method</li>
<li><a href="https://www.swyx.io/learn-in-public">Learn In Public</a> by swyx</li>
<li><a href="https://paulgraham.com/words.html">Putting Ideas into Words</a> by Paul Graham</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Learn New Things and Make Them Stick</title>
        <link>https://christofersandin.com/texts/learn-new-things-and-make-them-stick</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/learn-new-things-and-make-them-stick</guid>
        <pubDate>Sun, 18 May 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Mini-essay</category>
        
        <description>In my line of work, you need to be able to learn new things. But, how should you go about learning? I tend to write, and that works well for me, but according to Huberman Lab, testing yourself right after reading the material the first time makes an impact. Why? Because doing so offsets the brain&#039;s…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>In my line of work, you need to be able to learn new things. But, how should you go about learning? I tend to write, and that works well for me, but according to <cite>Huberman Lab</cite>, testing yourself right after reading the material the first time makes an impact.</strong></p>
</div>
<p>Why? Because doing so offsets the brain&#8217;s barrier to forgetting new information.</p>
<p>The key is doing this <strong>actively</strong>, compared to reading and listening. Even if you don’t get the test right, looking at the correct answer after you come up with an answer yourself helps the learning process.</p>
<p>This might be why writing a mini-essay, like this one, is a way of studying that works well for me. While writing it, I&#8217;m constantly checking my interpretation and validating it with the source material, making it a self-testing process.</p>
<p>According to research in this field, <strong>taking a self-test after reading new material helps you remember 50% more</strong> than if you don’t.</p>
<p>How to test yourself, then? Open-ended short-answer questions give the best results according to studies on the subject.</p>
<p>To help you even further, research points out the following essential prerequisites to set you up for learning:</p>
<ul>
<li>good (and enough) sleep</li>
<li>mindfulness (5-10 min/day makes a big difference)</li>
<li>focus and alertness</li>
<li>caffeine (minor gains)</li>
</ul>
<p>The studies also show that you get the best results by spending time studying in isolation. (Teaching others is a great way to deepen your knowledge after learning.)</p>
<p>Changes in the neuroplasticity in the brain make us learn and forget, and this process benefits from the advice above, <a href="https://www.hubermanlab.com/episode/optimal-protocols-for-studying-learning">according to Huberman</a>. For me, I&#8217;ll continue to write, but adding small practical examples along the way or quizzing myself while writing might be worth the effort!</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://www.retrievalpractice.org/">Retrieval Practice</a> by Pooja Agarwal</li>
<li><a href="https://learninglab.psych.purdue.edu/downloads/2007/2007_Karpicke_Roediger_JML.pdf">Repeated retrieval during learning is the key to long-term retention</a> by Karpicke &amp; Roediger (PDF)</li>
<li><a href="https://ncase.me/remember/">How To Remember Anything Forever-ish</a> by Nicky Case</li>
<li><cite><a href="https://www.makeitstick.com/">Make It Stick: The Science of Successful Learning</a></cite> by Brown, Roediger, and McDaniel</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Email — How Hard Can It Be?</title>
        <link>https://christofersandin.com/texts/email-how-hard-can-it-be</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/email-how-hard-can-it-be</guid>
        <pubDate>Sun, 18 May 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Article</category>
        
        <description>The first email was sent in 1971, and things haven&#039;t changed much since. So, how hard can it be? It&#039;s pretty hard. It&#039;s too easy to spoof and send fake emails, and many people have been tricked in one way or another. What can we do to stop people from using our email addresses for spam, spoofs, and…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>The first email was sent in 1971, and things haven&#8217;t changed much since. So, how hard can it be?</strong></p>
</div>
<p>It&#8217;s pretty hard. It&#8217;s too easy to spoof and send fake emails, and many people have been tricked in one way or another. What can we do to stop people from using our email addresses for spam, spoofs, and the phishing emails that are ever so popular?</p>
<p>Well, a few things. So let&#8217;s get started.</p>
<h2>DNS</h2>
<p>To fix email, or at least a small part of it, we need to dive deep into the <strong>DNS</strong> (short for the <em>Domain Name System</em>) and add a few records.</p>
<p>All devices on the Internet have an IP address, which looks something like <code>142.250.74.142</code>. But that is hard for humans to remember, so we need a way to make it more memorable, and that&#8217;s where DNS comes in. A DNS server translates between a human-readable address and the IP address used by machines. As I write this, the address above is the translated version of <code>google.com</code>.</p>
<p>To send reliable emails, you need the following records in your DNS:</p>
<ul>
<li>Sender Policy Framework (SPF)</li>
<li>DomainKeys Identified Mail (DKIM)</li>
<li>Domain-based Message Authentication, Reporting &amp; Conformance (DMARC)</li>
</ul>
<p>Let&#8217;s look at them one by one and how they are related.</p>
<h2>SPF</h2>
<p>This is a <code>TXT</code> record in the DNS stating which servers are allowed to send emails for the domain name. The receiver can then verify that the domain in the email&#8217;s <em>Return-Path</em> is included in the record.</p>
<p>The <code>TXT</code> record looks like this:</p>
<pre><code class="language-dns">v=spf1 a mx include:mydomain.com ~all
</code></pre>
<p>Note that you can <em>only have one SPF record in the DNS</em>, so include all domains that send emails on your behalf. These are often services like MailChimp, Postmark, or Klaviyo, and you might also have a CMS that sends emails, so make sure to include those.</p>
<p>If you need to have multiple domains, the record will look like this:</p>
<pre><code class="language-dns">v=spf1 a mx include:mydomain.com include:spf.mtasv.net ~all
</code></pre>
<p>Above are our <code>mydomain.com</code> and Postmark&#8217;s <code>spf.mtasv.net</code> added to the SPF record.</p>
<h2>DKIM</h2>
<p>The DKIM authentication method uses a classic private and public key pair setup. A public DKIM key is (also) a <code>TXT</code> record and looks something like this:</p>
<pre><code class="language-dns">v=DKIM1;t=s;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDBzXkunA  
132Pf3SwHF7UKTODjFW8JKXUFWCHcNLvRHPCFDzJDPuAuoZq0XAIoOStu+Qq+/  
ggm1zDYbgsaIkOmkBWV9m/NPQ3BbXNEnCqjsyVxWlrQs0R01W4ihsHM8BkbE7  
dGRot1DdDM1HBMxrMDEOPuEZaNjtpgcJVRqswz7YwIDAQAB
</code></pre>
<p> The <em>Email Service Provider</em> (ESP) uses the private key to cryptographically sign the sent email with a unique hash based on the private key and the message content. This hash is then placed in the message header.<br />
 <br />
 The public key, saved in the DNS, can be used by the receiver to verify that the message body and attachments were not altered in transit and are sent from a valid domain.</p>
<h2>DMARC</h2>
<p>DMARC ensures that you pass either SPF or DKIM and that your DNS records are set up correctly. If not, the email will not be delivered. That is a little scary, but you can set up DMARC without quarantining or rejecting emails initially.</p>
<p>Why would you do this, then? I&#8217;ll tell you. The ESPs that support DMARC will send a DMARC report to the <code>rua</code> email address stated in the record.</p>
<p>This report is in XML format, but many (free) tools will help you parse and summarize it. If you&#8217;d like to get started, I recommend Postmark&#8217;s free DMARC reporting tool. Then, monitor it for a while, and when you&#8217;re happy with the results, move to the stricter quarantine or reject policy.</p>
<p>Ok, that sounds good, then. But how do we implement DMARC?</p>
<p>Yes, you&#8217;re right. We will implement it in the DNS with a <code>TXT</code> record. Who would have guessed…</p>
<p>And that one will look something like this:</p>
<pre><code class="language-dns">v=DMARC1; p=none; sp=none; pct=100; rua=mailto:example@yourdomain.com;
</code></pre>
<p>The domain owner publishes a DMARC policy in their DNS with recommendations on how they would like receivers to process their mail based on SPF and DKIM authentication results.</p>
<p>This policy applies to all mail using that domain in the From header of the email. <strong>For DMARC to pass, either SPF or DKIM must pass <em>and</em> align with the DMARC domain</strong>.</p>
<p>If you send a lot of emails, more than 5000 emails a day, you need to read up on the &quot;Yahoo and Google DMARC requirement&quot; that came into force on February 1, 2024. To continue to have reliable delivery, the messages must pass DMARC Alignment, or they will not be delivered.</p>
<h2>One more thing — BIMI</h2>
<p>Another <em>nice-to-have</em> is adding a <em>Brand Indicators for Message Identification</em> (BIMI) <code>TXT</code> record to visualize your logo next to the emails you send. To add BIMI, you need to have:</p>
<ul>
<li>SPF and/or DKIM authentication alignment</li>
<li>DMARC enforcement (either p=quarantine or p=reject)</li>
</ul>
<p>So, after getting your DMARC set up and verifying that you don&#8217;t send emails from sources other than those you have included in your policy, you can force the emails to be <em>quarantined</em> or <em>rejected</em>.</p>
<p>This is a prerequisite for a BIMI implementation, so ensure your DMARC policy is set to enforcement mode (<code>p=quarantine</code> or <code>p=reject</code>) before implementing BIMI.</p>
<p>You can also <a href="https://easydmarc.com/blog/what-are-verified-mark-certificates/">verify your logo</a> with a Verified Mark Certificate (VMC), even if it&#8217;s not a hard requirement.</p>
<p>When ready, you can, for instance, use the <a href="https://easydmarc.com/tools/bimi-record-generator">BIMI Record Generator</a> by EasyDMARC to put everything in place.</p>
<hr />
<h2>References</h2>
<p>Cloudflare has a set of good articles explaining DNS and the different records used to implement SPF, DKIM, and DMARC.</p>
<ul>
<li><a href="https://www.cloudflare.com/learning/dns/what-is-dns/">What is DNS</a></li>
<li><a href="https://www.cloudflare.com/learning/dns/dns-records/dns-spf-record/">What is a DNS SPF record?</a></li>
<li><a href="https://www.cloudflare.com/learning/dns/dns-records/dns-dkim-record/">What is a DNS DKIM record?</a></li>
<li><a href="https://www.cloudflare.com/learning/dns/dns-records/dns-dmarc-record/">What is a DNS DMARC record?</a></li>
</ul>
<p>As do Postmark</p>
<ul>
<li><a href="https://postmarkapp.com/guides/spf">SPF record: Protect your domain reputation and email delivery</a></li>
<li><a href="https://postmarkapp.com/guides/dkim">DKIM: What is it and why is it important when sending emails?</a></li>
<li><a href="https://postmarkapp.com/guides/dmarc">DMARC: What is it and why do you need it?</a></li>
</ul>
<p><strong>Articles</strong></p>
<ul>
<li><a href="https://internetstiftelsen.se/guide/dns-internets-vagvisare/sa-fungerar-dns/">Vad är DNS?</a> (in Swedish)</li>
<li><a href="https://dmarcian.com/yahoo-and-google-dmarc-required/">Understanding Gmail and Yahoo DMARC Requirements</a></li>
<li><a href="https://postmarkapp.com/guides/transactional-email-best-practices">Transactional Email Best Practices</a> by Postmark</li>
</ul>
<p><strong>Other related resources</strong></p>
<ul>
<li><a href="https://zonemaster.se/en/run-test">Zonemaster</a> - a domain test service published in the <a href="https://internetstiftelsen.se/dns-labs/about-dns-labs/">DNS-Labs</a> from <a href="https://internetstiftelsen.se/en/">The Swedish Internet Foundation</a>, &quot;an independent, business-driven and public-benefit organization&quot; that is &quot;working for an internet that contributes positively to people and society&quot;.</li>
<li><a href="https://support.google.com/a/answer/180504?hl=en">Turn on DKIM for your domain</a> by Google Workspace Admin Help</li>
<li><a href="https://support.google.com/a/answer/10032674?hl=en">Before you set up DMARC</a> and <a href="https://support.google.com/a/answer/2466563?hl=en">Add your DMARC record</a> by Google Workspace Admin Help</li>
<li><a href="https://support.google.com/mail/answer/81126">Email sender guidelines</a> by Google – the requirements behind the 2024 bulk-sender rules</li>
</ul>
<p><strong>Tools</strong></p>
<ul>
<li><a href="https://mxtoolbox.com/dmarc.aspx">DMARC Check Tool</a> by MxToolbox</li>
<li><a href="https://dmarcian.com/domain-checker/">DMARC Domain Checker</a> by dmarcian</li>
<li><a href="https://easydmarc.com/tools/bimi-record-generator">BIMI Record Generator</a> by EasyDMARC</li>
<li><a href="https://www.learndmarc.com/">Learn DMARC</a> – send it an email and watch SPF, DKIM, and DMARC validation step by step</li>
<li><a href="https://www.mail-tester.com/">Newsletters spam test</a> by mail-tester.com</li>
</ul>
<p><strong>Standards</strong></p>
<ul>
<li><a href="http://www.open-spf.org/">Open SPF</a></li>
<li><a href="https://dkim.org/">DKIM</a></li>
<li><a href="https://dmarc.org/">DMARC</a></li>
<li><a href="https://datatracker.ietf.org/doc/html/rfc9989">DMARCbis, RFC 9989</a> – the current DMARC specification</li>
<li><a href="https://bimigroup.org/">BIMI Group</a> – the industry group behind BIMI</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: Exploring Vim after 20 Years of Writing Code</title>
        <link>https://christofersandin.com/texts/terminal-exploring-vim-after-20-years-of-writing-code</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-exploring-vim-after-20-years-of-writing-code</guid>
        <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>As a middle-aged CEO and developer, I&#039;ve found myself increasingly occupied with running the company and maintaining a general project overview lately. I needed something new to explore. Therefore, after more than 20 years of coding in regular text editors and IDEs, I decided to explore Vim. Why?…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>As a middle-aged CEO and developer, I&#8217;ve found myself increasingly occupied with running the company and maintaining a general project overview lately. I needed something new to explore. Therefore, after more than 20 years of coding in regular text editors and IDEs, I decided to explore <em>Vim</em>.</strong></p>
</div>
<p>Why? There was no particular reason; I was just a little curious and needed a challenge. I did like the idea that you spend more time editing than writing, so there should be a specific mode for that.</p>
<p>This text is not a general introduction to Vim — there are many available on the Internet — but I have written down a few notes from that endeavor.</p>
<hr />
<p>The whole thing did not start with Vim. At first, I took a look at <a href="https://helix-editor.com">Helix</a>. Helix is an editor that functions similarly to Vim and Neovim. It&#8217;s fast, written in Rust, and requires almost zero configuration. I liked it a lot and spent some time in it. It took a bit of getting used to working in different modes, but I could see the appeal.</p>
<p>Helix is still a very niche product, and after reading and reviewing tutorials, I switched to <a href="https://neovim.io">Neovim</a> mainly because of the extensive amount of material and plugins available. Neovim is an extension of Vim, so learning this provides a solid foundation for Vim motions as well. I also liked learning <a href="https://www.lua.org">Lua</a>, the programming language used to configure Neovim.</p>
<p>Many people suggest starting <code>nvim</code>, pressing the <code>&lt;ESC&gt;</code> key, typing <code>:Tutor</code>, and then <code>&lt;ENTER&gt;</code> if you need help with the basics.</p>
<p>Another great place to start is to go all-in on the <a href="https://github.com/nvim-lua/kickstart.nvim">kickstart.nvim</a> project. You can also read the project&#8217;s <a href="https://github.com/nvim-lua/kickstart.nvim/blob/master/init.lua">config file</a>, which is full of comments and ideas, directly on GitHub and pick and choose the things you like.</p>
<p>Both approaches are good options and might suit you, but I needed to see what was doable, so I started watching some &quot;set up Neovim from scratch&quot; videos on YouTube to get into it.</p>
<p>Have I switched to Neovim exclusively? No, I have not. Have I gained insights into what&#8217;s out there? Yes, I have. Currently, I&#8217;m in the middle, but I can see myself using an editor with Vim key bindings soon.</p>
<hr />
<h2>Key bindings</h2>
<p>The most interesting aspect of Vim and Vim-based editors is learning how to work in different modes.</p>
<h2>Normal mode</h2>
<p>You start in normal mode, which is your base, and all interactions begin here. Move around files and select what to edit.</p>
<h3>Navigation</h3>
<ul>
<li>
<p>Left, down, up, right <code>h</code> <code>j</code> <code>k</code> <code>l</code></p>
</li>
<li>
<p>Start of line <code>0</code> / End of line <code>$</code></p>
</li>
<li>
<p><code>f @</code>- move cursor to next occurrence of <strong>@</strong>, i.e., <code>f _</code> move to next _</p>
</li>
<li>
<p><code>t @</code> - move cursor to character <strong>before</strong> next <strong>@</strong>.</p>
</li>
<li>
<p>Next word <code>w</code> / WORD <code>W</code></p>
</li>
<li>
<p>Previous word <code>b</code> / WORD <code>B</code></p>
</li>
<li>
<p>End of next word <code>e</code> / WORD <code>E</code></p>
</li>
<li>
<p>Previous blank line <code>{</code> / Next blank line <code>}</code></p>
</li>
<li>
<p>Previous sentence <code>(</code> / Next sentence <code>)</code></p>
</li>
<li>
<p>Move cursor to first line of document <code>gg</code></p>
</li>
<li>
<p>Move cursor to last line of document <code>G</code></p>
</li>
<li>
<p>Move cursor to last insert point <code>gi</code></p>
</li>
<li>
<p>Move cursor to line <code>#</code> - <code>#G</code></p>
</li>
<li>
<p>Go <code>#</code> lines down - <code>#j</code> / Go <code>#</code> lines up - <code>#k</code></p>
</li>
<li>
<p>Move up a screen <code>Ctrl u</code></p>
</li>
<li>
<p>Move down a screen <code>Ctrl d</code></p>
</li>
<li>
<p>Substitute line (delete line, enter insert mode) <code>S</code></p>
</li>
</ul>
<h3>Editing text</h3>
<p><strong>Edit</strong></p>
<ul>
<li><code>a</code> - add</li>
<li><code>i</code> - insert</li>
</ul>
<ul>
<li>
<p><code>A</code> - start editing at the end of the line</p>
</li>
<li>
<p><code>I</code> - start editing at the beginning of the line</p>
</li>
<li>
<p><code>D</code> - delete to end of line</p>
</li>
<li>
<p><code>C</code> - change text to end of line</p>
</li>
<li>
<p><code>.</code> - repeat the last change</p>
</li>
</ul>
<ul>
<li><code>ciw</code> - Change Inner Word</li>
</ul>
<p><strong>Folding code</strong></p>
<ul>
<li><code>zR</code> - Open all</li>
</ul>
<ul>
<li><code>zM</code> - Collapse all</li>
<li><code>zo</code> - Open</li>
<li><code>zO</code> - Open all from the current location</li>
<li><code>zc</code> - Close</li>
<li><code>zC</code> - Close all from the current location</li>
<li><code>za</code> - Toggle current fold</li>
<li><code>zi</code> - Toggle code folding</li>
</ul>
<p><strong>Quit vim</strong></p>
<ul>
<li><code>ZZ</code></li>
</ul>
<p><strong>Auto-complete</strong></p>
<ul>
<li><code>Ctrl P/N</code></li>
</ul>
<p><strong>Selection</strong></p>
<ul>
<li>Select current word - <code>*</code></li>
</ul>
<h3>Spelling</h3>
<ul>
<li>Go to previous and next spelling mistake - <code>[s</code> and <code>]s</code></li>
<li>Spell check current word - <code>z=</code></li>
<li>Add current word to spell check - <code>zg</code></li>
<li>Remove current word from spell checker - <code>zG</code></li>
</ul>
<h2>Files and buffers</h2>
<p>An open file lives in a buffer. You can display multiple buffers at the same time, and you can have the same file open in many buffers.</p>
<h3>Buffers</h3>
<ul>
<li><code>:ls</code> - List buffers</li>
<li><code>:bn</code> - Next buffer</li>
<li><code>:bp</code> - Previous buffer</li>
<li><code>:bw</code> - Close buffer</li>
<li><code>:bd#</code> - Close buffer #</li>
</ul>
<h3>Splits</h3>
<ul>
<li><code>:sp</code> - split horizontally</li>
<li><code>:vs</code> - split vertically</li>
<li><code>ZQ</code> - quit without saving (same as <code>:q!</code>)</li>
</ul>
<ul>
<li>Go between split windows with <code>Ctrl w</code> and the Vim keys (<code>h</code>or <code>l</code> for left and right, <code>j</code> and <code>k</code> for up and down)</li>
</ul>
<h2>Macros</h2>
<p>Record interactions and reuse them with macros.</p>
<p><strong>Recordings</strong></p>
<ol>
<li>Record: <code>q a</code> (keystrokes) <code>q</code></li>
<li>Play: <code>@ a</code></li>
<li>Play multiple (15) times: <code>15@a</code></li>
</ol>
<hr />
<h2>Visual mode</h2>
<p>Working in visual mode allows you to select text and view a visual representation of what you have selected.</p>
<p><strong>Select a paragraph</strong></p>
<ul>
<li><code>Vap</code> - <em>select</em> <strong>around</strong> the current <strong>paragraph</strong></li>
<li><code>Vip</code> - <em>select</em> <strong>inside</strong> the current <strong>paragraph</strong></li>
</ul>
<p><strong>Select block</strong></p>
<ul>
<li><code>v%</code> - <em>select</em> from the current position to the next matching character</li>
</ul>
<p><strong>Select until next instance</strong></p>
<ul>
<li><code>v/foo</code> - <em>select</em> from your current position to the next instance of <strong>foo</strong>, and <code>n</code> expands to the next instance.</li>
</ul>
<p><strong>Select Word</strong></p>
<ul>
<li><code>viw</code> and <code>viW</code></li>
</ul>
<p><strong>Copy a word and replace another word</strong></p>
<ul>
<li>To copy a word under the cursor, press <code>bvey</code></li>
<li>To replace the word under the cursor, press <code>bvep</code></li>
</ul>
<hr />
<h2>Insert mode</h2>
<ul>
<li><code>Ctrl o</code> - temporarily enter Normal mode.</li>
<li><code>Ctrl w</code> - delete the word to the left of the cursor.</li>
<li><code>Ctrl u</code> - delete from the cursor to the beginning of the line.</li>
</ul>
<hr />
<h2>Third-party plugins</h2>
<p>Before committing to third-party plugins and extensions, it is wise to explore the basic commands in your applications. It is also always a good idea to keep dependencies to a minimum.</p>
<p>That said, there are a few plugins that significantly enhance the user experience in Neovim, and if they have a good reputation and solid support, I&#8217;m not opposed to using them.</p>
<h3>The foundation</h3>
<p>From what I gathered during my research, it appears that <a href="https://github.com/folke/lazy.nvim">lazy.nvim</a> is a reliable way to manage plugins.</p>
<p>Here is a list of the ones that function as a foundation for my setup:</p>
<ul>
<li>Package manager for downloading plugins (lazy.nvim)</li>
<li>Download LSPs, formatters, and linters (mason.nvim)</li>
<li><a href="https://github.com/nvim-treesitter/nvim-treesitter">nvim-treesitter</a> - syntax highlighting</li>
<li><a href="https://github.com/nvim-treesitter/nvim-treesitter-textobjects">nvim-treesitter-textobjects</a> - working with text objects</li>
</ul>
<h2>File pickers</h2>
<h3>telescope.nvim</h3>
<p><a href="https://github.com/nvim-telescope/telescope.nvim"><em>Telescope</em></a> is an extendable fuzzy finder over lists for Neovim. It is &quot;built on the latest awesome features from Neovim core,&quot; which I guess must be good. It is centered around modularity, allowing for easy customization.</p>
<pre><code>vim.keymap.set(&quot;n&quot;, &quot;&lt;leader&gt;&lt;leader&gt;&quot;, builtin.oldfiles, {})
vim.keymap.set(&quot;n&quot;, &quot;&lt;leader&gt;ff&quot;, builtin.find_files, {})
vim.keymap.set(&quot;n&quot;, &quot;&lt;leader&gt;fg&quot;, builtin.live_grep, {})
vim.keymap.set(&quot;n&quot;, &quot;&lt;leader&gt;fb&quot;, builtin.buffers, {})
vim.keymap.set(&quot;n&quot;, &quot;&lt;leader&gt;fr&quot;, builtin.registers, {})
</code></pre>
<h2>File explorers</h2>
<h3>oil.nvim</h3>
<p>If you like to step away from the file tree view on the left-hand side of the code and use a more native-feeling solution, you want to try <a href="https://github.com/stevearc/oil.nvim">oil.nvim</a>.</p>
<p>Hitting the <kbd>-</kbd> key displays a list of the current directory, and you can use your Vim skills to add, delete, and rename files.</p>
<p>Using <code>g</code> will display other options if you have <a href="https://github.com/folke/which-key.nvim">Which Key</a> installed.</p>
<p>Currently, this is my preferred method for quickly and easily performing file-related tasks within Neovim.</p>
<h2>Code formatting and auto-complete</h2>
<ul>
<li>Formatting code (conform.nvim)</li>
<li>Linting code (nvim-lint)</li>
<li>Syntax highlighting and code completion with LSPs
<ul>
<li><a href="https://github.com/neovim/nvim-lspconfig">nvim-lspconfig</a> - LSP interaction</li>
<li><a href="https://github.com/Saghen/blink.cmp">blink.cmp</a> - code completion with support for LSPs and external sources</li>
</ul>
</li>
</ul>
<h3>nvim-surround</h3>
<p>Surround text with a character or a tag.</p>
<ul>
<li><code>add</code> with <code>ys{motion}{char}</code></li>
<li><code>delete</code> with <code>ds{char}</code></li>
<li><code>change</code> with <code>cs{target}{replacement}</code></li>
</ul>
<p><code>ysiw)</code> – add &quot;(&quot; and &quot;)&quot; around word<br />
<code>ys$t</code> - adds a tag around the text from the cursor position to the end of the line</p>
<p><code>ds&quot;</code> - delete &quot; around text<br />
<code>dst</code> - delete tag around text</p>
<p><code>cs'&quot;</code> - change quotes from <code>'</code> to <code>&quot;</code></p>
<h3><a href="https://github.com/numToStr/Comment.nvim">// Comment.nvim</a></h3>
<p>Comment your code in style.</p>
<ul>
<li>
<p>NORMAL mode</p>
<ul>
<li><code>gcc</code> - Toggles the current line using a line-wise comment</li>
<li><code>gbc</code> - Toggles the current line using a block-wise comment</li>
</ul>
</li>
<li>
<p>VISUAL mode</p>
<ul>
<li><code>gc</code> - Toggles the region using a line-wise comment</li>
<li><code>gb</code> - Toggles the region using a block-wise comment</li>
</ul>
</li>
</ul>
<h2>LSP</h2>
<h3>nvim-lspconfig</h3>
<p>Nvim supports the Language Server Protocol (LSP), which means it acts as a client to LSP servers. LSP is a standard that lets different editors understand how programming languages work; it originated at <a href="https://microsoft.github.io/language-server-protocol/">Microsoft</a>. This is the official plugin used to make Neovim use LSPs.</p>
<blockquote>
<p>LSP facilitates features like go-to-definition, find references, hover, completion, rename, format, refactor, etc., using semantic whole-project analysis</p>
</blockquote>
<h3>trouble.nvim</h3>
<p>This is a way to look at the diagnostics that the LSP server provides, both for individual files and for the whole project.</p>
<blockquote>
<p>A pretty list for showing diagnostics, references, telescope results, quickfix and location lists to help you solve all the trouble your code is causing.</p>
</blockquote>
<p><a href="https://github.com/folke/trouble.nvim">trouble.nvim on GitHub</a></p>
<h2>Putting a smile on your face</h2>
<p>These are the others I use at the moment:</p>
<ul>
<li>
<p>Interface/UX</p>
<ul>
<li><a href="https://github.com/goolord/alpha-nvim">α alpha-nvim</a> - start up Neovim with style</li>
<li><a href="https://github.com/nvim-lualine/lualine.nvim">lualine.nvim</a> - easy to configure Neovim status line</li>
<li><a href="https://github.com/norcalli/nvim-colorizer.lua">colorizer.lua</a> - display your color codes in color</li>
<li><a href="https://github.com/NMAC427/guess-indent.nvim">:GuessIndent</a> - fast indentation style detection written in Lua</li>
<li><a href="https://github.com/folke/noice.nvim">Noice (Nice, Noise, Notice)</a> - completely replaces the UI for <em>messages</em>, <em>cmdline</em>, and the <em>popup menu</em>.</li>
</ul>
</li>
<li>
<p>Navigation</p>
<ul>
<li><a href="https://github.com/alexghergh/nvim-tmux-navigation">Neovim-Tmux Navigation</a> - navigate between tmux and Neovim</li>
</ul>
</li>
<li>
<p>Git</p>
<ul>
<li><a href="https://github.com/tpope/vim-fugitive">fugitive.vim</a> - working with Git inside Neovim (haven&#8217;t had time to explore, but the name alone puts it on the list)</li>
<li><a href="https://github.com/lewis6991/gitsigns.nvim">gitsigns.nvim</a> - deep buffer integration for Git</li>
</ul>
</li>
</ul>
<hr />
<h2>Links</h2>
<h3>References and videos</h3>
<ul>
<li>
<p>&quot;Neovim from scratch&quot; by Mr Jakob</p>
<ul>
<li><a href="https://www.youtube.com/watch?v=g1gyYttzxcI">Part 1: lazy.nvim, kanagawa.nvim, oil.nvim, Statusline &amp; Essential Settings</a></li>
<li><a href="https://www.youtube.com/watch?v=E4qXZv34NQQ">Part 2: Supercharged Code Navigation via Treesitter, Textobjects &amp; which-key</a></li>
<li><a href="https://www.youtube.com/watch?v=R3e7uAE8jjo">Part 3: Insanely fast Neovim Navigation with fzf ❤️ lua</a></li>
<li><a href="https://www.youtube.com/watch?v=b17g20II6SQ">Part 4: Code Intelligence in Neovim - The LSP Setup that grants you IDE Powers</a></li>
<li><a href="https://www.youtube.com/watch?v=UVO_cq3xATo&amp;t=137s">Part 5: Perfect Code Formatting with conform.nvim</a></li>
<li><a href="https://www.youtube.com/watch?v=GKIxgCcKAq4">Part 6: blink-cmp: Lightning-Fast Autocompletion Built in Rust</a></li>
</ul>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=6pAG3BHurdM">How I Setup Neovim To Make It AMAZING in 2024: The Ultimate Guide</a> by Josean Martinez</p>
</li>
<li>
<p><a href="https://youtube.com/watch?v=ybUE4D80XSk">How To Setup Linting And Formatting In Neovim To Replace null-ls</a> by Josean Martinez</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=m8C0Cq9Uv9o">The Only Video You Need to Get Started with Neovim</a> by TJ DeVries</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=iqdCshrIKIg">telescope.nvim introduction</a> by TJ DeVries</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=mEqqkHLhlGY">Code Formatting made easy</a> by TJ DeVries</p>
</li>
<li>
<p><a href="https://www.youtube.com/watch?v=w7i4amO_zaE&amp;t=37s">0 to LSP : Neovim RC From Scratch</a> by ThePrimeagen</p>
</li>
<li>
<p><a href="https://github.com/xero/evangelion.nvim">Vim Color scheme &#8216;evangelion&#8217;</a></p>
</li>
<li>
<p><a href="https://gist.githubusercontent.com/liocer/ce1485f9f4971fec4877fae7de2fbfc4/raw/efd6010e9eb4c1d0a2475de99cc4b56f0abcf828/nv.asc">Neovim Ascii Logo by rc!</a></p>
</li>
</ul>
<h3>Official links to repo and plugins</h3>
<ul>
<li>
<p><a href="https://neovim.io/">Neovim</a></p>
</li>
<li>
<p><a href="https://www.nerdfonts.com/">Nerdfonts</a></p>
</li>
<li>
<p><a href="https://github.com/nvim-telescope/telescope.nvim">Telescope</a></p>
</li>
<li>
<p><a href="https://github.com/stevearc/oil.nvim">Oil</a></p>
</li>
<li>
<p><a href="https://github.com/nvim-neo-tree/neo-tree.nvim">Neo-tree</a></p>
</li>
</ul>
<h3>Themes</h3>
<ul>
<li><a href="https://github.com/zenbones-theme/zenbones.nvim">Zenbones</a></li>
</ul>
<h3>Guides</h3>
<ul>
<li><a href="https://github.com/iggredible/Learn-Vim">Learn Vim (the Smart Way)</a> – a free book bridging the gap between <code>:Tutor</code> and <code>:help</code></li>
<li><a href="https://dn.ht/intermediate-vim">Intermediate Vim</a> by Dennis Hotson</li>
<li><a href="https://www.lazyvim.org/">LazyVim</a> – a popular preconfigured Neovim distribution, if you&#8217;d rather not build the stack yourself</li>
<li><a href="https://dotfyle.com/">Dotfyle</a> – discover Neovim plugins and browse real-world configs</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: The Konami Code for Your Terminal</title>
        <link>https://christofersandin.com/texts/terminal-the-konami-code-for-your-terminal</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-the-konami-code-for-your-terminal</guid>
        <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>To make the terminal on macOS a bit nicer, I thought we could use the famous Konami Code to give our friend some extra functions that improve everyday life. These are entirely subjective opinions from someone who uses the terminal more often now than before. Many things are much faster to do there…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>To make the terminal on macOS a bit nicer, I thought we could use the famous <em>Konami Code</em> to give our friend some extra functions that improve everyday life.</strong></p>
</div>
<p>These are entirely subjective opinions from someone who uses the terminal more often now than before. Many things are much faster to do there compared to doing the same thing in other programs and interfaces, so once you get used to it, it&#8217;s hard to stop.</p>
<p>It&#8217;s also time for me to change computers, and it would be nice to have a guide to follow, since I always start every new computer with a completely fresh installation. This approach provides a fresh start and is a strategy that has worked well for me for nearly twenty years.</p>
<p>However, in addition to mentally pressing the classic code ⬆️ ⬆️ ⬇️ ⬇️ ⬅️ ➡️ ⬅️ ➡️ 🅱️ 🅰️, you need to take a couple more steps.</p>
<p>Stay tuned!</p>
<hr />
<h2>⬆️ ⬆️ – Install the basics</h2>
<p>A few things are essential, and if you&#8217;re going to work with some form of development on a Mac, these are some of the first things you need to install to have a functioning environment.</p>
<ul>
<li>Xcode</li>
<li>Node.js</li>
<li>Homebrew</li>
<li>iTerm2 (or other terminal application)</li>
</ul>
<h3>Install the CLI Tools for Xcode</h3>
<p>You can certainly install the full <em>Xcode</em> via the App Store, but isn’t it convenient to get the Command Line Tools through the terminal instead?</p>
<pre><code>xcode-select --install
</code></pre>
<h3>Install Node.js and npm</h3>
<p>Start by following the instructions at <a href="https://nodejs.org/en/">https://nodejs.org/en/</a>.</p>
<p>Then, one more thing makes everyday life smoother: install all global packages in your home directory instead of the system directory (the default). We do this to avoid permission issues and having to type <code>sudo</code> before all npm installations for all eternity…</p>
<pre><code>mkdir ~/.npm-global 
npm config set prefix '~/.npm-global'
</code></pre>
<p>We also need to add the path in <code>.zshrc</code> so that we can use the packages from anywhere:</p>
<pre><code># Node.js global folder in ~/.npm-global
export PATH=~/.npm-global/bin:$PATH
</code></pre>
<h2>Homebrew</h2>
<p><em>Homebrew</em> is a package manager for macOS. Let’s install it and then use that to install the other packages.</p>
<pre><code>/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;
</code></pre>
<h2>Install a new terminal emulator</h2>
<p>I use <em>iTerm2</em> instead of the built-in terminal. Several little things are quite a lot nicer, and I’ve gotten used to them.</p>
<p>There are other options today, and I’m currently testing both <a href="https://ghostty.org/">Ghostty</a> and <a href="https://wezfurlong.org/wezterm/index.html">WezTerm</a>, but &quot;if it ain&#8217;t broke, don&#8217;t fix it&quot; works for me in this case.</p>
<pre><code>brew install --cask iterm2
</code></pre>
<p>To make adjustments, you modify the file <code>.zshrc</code>:</p>
<pre><code>vim ~/.zshrc
</code></pre>
<h2>⬇️ ⬇️ – Install &quot;Oh My Zsh&quot;</h2>
<p>Nowadays, macOS comes with <em>Zsh</em> as the shell instead of <em>Bash</em>.</p>
<p>I have been using Zsh for many years, so this is something I appreciate, but to make Zsh even better, an easy win is to install <em>Oh My Zsh</em>:</p>
<pre><code>sh -c &quot;$(curl -fsSL https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh)&quot;
</code></pre>
<h2>Plugins</h2>
<p>I use a few external plugins that need to be installed and some that come included but need to be activated in <code>.zshrc</code>.</p>
<ul>
<li>zsh-autosuggestions</li>
<li>k</li>
</ul>
<p>With the two installed above, my <code>.zshrc</code> looks like this:</p>
<pre><code>plugins=(git npm extract k)
source $ZSH/oh-my-zsh.sh
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
</code></pre>
<h3>Themes</h3>
<p>There are also a number of different themes, and right now, I’m using <em>af-magic</em>, which I’m pretty happy with.</p>
<h2>⬅️ – Fonts with superpowers</h2>
<p>To get a bit more out of the terminal, you can install some <em>Nerd Fonts</em>. Here, we install it together with the Hack typeface.</p>
<pre><code>brew tap homebrew/cask-fonts
brew install --cask font-hack-nerd-font
</code></pre>
<h2>➡️ – Nicer colors</h2>
<p>To improve the colors in the terminal, I like <em>vivid</em>, which I came across recently. We use Homebrew again to install:</p>
<pre><code>brew install vivid
</code></pre>
<p>One little &quot;gotcha&quot; is that you also need to install the GNU version of <code>ls</code> instead of the BSD version included with macOS to be able to use the colors:</p>
<pre><code>brew install coreutils
</code></pre>
<p>Then you can set the colors you want to use along with a little alias in <code>.zshrc</code> to make everything look tidy:</p>
<pre><code># Vivid colors
export LS_COLORS=&quot;$(vivid generate molokai)&quot;
alias ls=&quot;gls --color&quot;
</code></pre>
<p>Here with the <em>molokai</em> colors.</p>
<p>Note: Another approach is to skip this step and let the various tools inherit the color scheme you have defined for your terminal.</p>
<h2>⬅️ – More superpowers</h2>
<p>I use about a dozen commands in the terminal most of the time, but there are a few commands that I benefit from every day, and the most used is <code>z</code>, which this list starts with. The others are good, too, but they&#8217;re used much less frequently.</p>
<h3>z / zoxide</h3>
<p>If there’s one command you should install, it’s <code>z</code>. With <code>z</code>, you can jump around among the directories you use the most using fuzzy shortcuts.</p>
<pre><code>brew install z
</code></pre>
<p>Add to <code>.zshrc</code>:</p>
<pre><code># z
. $(brew --prefix)/etc/profile.d/z.sh
</code></pre>
<p>This means you can type <code>z site</code> instead of <code>cd ~/Sites</code>, for a simple example. It is invaluable if you work in the terminal.</p>
<p><em>Zoxide</em> is a more modern version of <code>z</code> above. It&#8217;s a little faster and has support for <code>fzf</code>, which makes it a bit more versatile. Works more or less in the same way:</p>
<pre><code> brew install zoxide
</code></pre>
<p>Add to <code>.zshrc</code>:</p>
<pre><code># zoxide
eval &quot;$(zoxide init zsh)&quot;
</code></pre>
<p>This will give you access to another <code>z</code> command, as well as the <code>zi</code> command, which shows an interactive display of matches.</p>
<p>Use <code>z</code> OR <code>zoxide</code>.</p>
<h3>lsd</h3>
<p>With Nerd Fonts in place, we can also install <em>LSD</em>, which stands for LSDeluxe and nothing else, using Homebrew:</p>
<pre><code>brew install lsd
</code></pre>
<p>I’m not the biggest fan, but it might suit you.</p>
<h3>htop / btop</h3>
<p>It’s not something I use daily, but <em>htop</em> is an updated version of <em>top</em> that shows active processes and memory usage in the terminal. It can be installed with:</p>
<pre><code>brew install htop
</code></pre>
<p>Or, if you would rather, go with the even better-looking one called <em>btop</em></p>
<pre><code>brew install btop 
</code></pre>
<h3>tldr</h3>
<p>You can use <code>man</code> to get help with syntax and other things, but these summaries are often very long and quite complicated to read. To make things easier, you can use <code>tldr</code>, which stands for &quot;too long, didn’t read&quot;, by installing it with npm:</p>
<pre><code>npm install -g tldr
</code></pre>
<p>This means we can now run <code>tldr ln</code> instead:</p>
<pre><code> ln

  Creates links to files and directories.
  More information: https://www.gnu.org/software/coreutils/ln.

  - Create a symbolic link to a file or directory:
	ln -s /path/to/file_or_directory path/to/symlink

  - Overwrite an existing symbolic link to point to a different file:
	ln -sf /path/to/new_file path/to/symlink

  - Create a hard link to a file:
	ln /path/to/file path/to/hardlink
</code></pre>
<p>Compare that to <code>man ln</code> if you can handle it…</p>
<h3>trash</h3>
<p>Sometimes, it’s nice for files that you delete to go to the trash first.</p>
<p>In the terminal, <code>rm</code> deletes files permanently right away. Not great if it’s a mistake… Add the command <code>trash</code> to send files to the trash instead.</p>
<pre><code>brew install trash
</code></pre>
<h3>neofetch</h3>
<p>Then everyone benefits from a bit of nice ASCII graphics in their terminal, so remember to install <em>neofetch</em> with:</p>
<pre><code>brew install neofetch
</code></pre>
<h2>➡️ – Restart after changes</h2>
<p>Every time you make a change in <code>.zshrc</code>, you need to restart the session for the change to take effect.</p>
<p>You can, of course, just close iTerm and start it again, but it’s easier to do <code>exec zsh</code> or <code>source ~/.zshrc</code>.</p>
<h2>🅱️ 🅰️ – In summary</h2>
<p>Now, finish by pressing 🅱️ and then 🅰️ to complete the Konami code, and the terminal will be significantly nicer the next time you sit down at the computer to get something done.</p>
<p>Epic win! ✌🏻</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://www.robinwieruch.de/mac-setup-web-development/">Mac Setup for Web Development</a> by Robin Wieruch – an actively maintained fresh-Mac guide</li>
<li><a href="https://sourabhbajaj.com/mac-setup/">macOS Setup Guide</a> by Sourabh Bajaj</li>
<li><a href="https://github.com/ajeetdsouza/zoxide">zoxide</a> – installation and shell setup for the modern <code>z</code></li>
<li><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Plugins">Oh My Zsh Plugins wiki</a> – the full catalog of bundled plugins</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: Yazi</title>
        <link>https://christofersandin.com/texts/terminal-yazi</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-yazi</guid>
        <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>Yazi is a Terminal-based file manager. It also has a few Vim-related key maps so it kind of fits into my little mini-series of articles around the Term. It has a column of files and folders on the left, a list of the files and folders in the current path in the middle, and a preview of the file on…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong><em>Yazi</em> is a Terminal-based file manager. It also has a few <em>Vim</em>-related key maps so it kind of fits into my little mini-series of articles around the Term.</strong></p>
</div>
<p>It has a column of files and folders on the left, a list of the files and folders in the current path in the middle, and a preview of the file on the right-hand side.</p>
<p>It also has support for Vim key bindings, which makes it quite intuitive to navigate if you have spent some time in Vim or <em>Neovim</em>. You use <code>y</code> to yank (copy) a file, you use <code>p</code> to paste, etc.</p>
<h2>Install</h2>
<p>Install all dependencies and <a href="https://yazi-rs.github.io/">Yazi</a> with <a href="https://brew.sh/">Homebrew</a>:</p>
<pre><code class="language-shell">brew install yazi ffmpeg sevenzip jq poppler fd ripgrep fzf zoxide imagemagick font-symbols-only-nerd-font
</code></pre>
<p>Or, if you want to run the latest development build instead:</p>
<pre><code class="language-shell">brew install yazi --HEAD
</code></pre>
<h2>Default configuration files</h2>
<p>Copy and paste these files to your own configuration and change the things you like.</p>
<ul>
<li><code>~/.config/yazi/</code><a href="https://github.com/sxyazi/yazi/blob/shipped/yazi-config/preset/theme-dark.toml">theme.toml</a></li>
<li><code>~/.config/yazi/</code><a href="https://github.com/sxyazi/yazi/blob/shipped/yazi-config/preset/keymap-default.toml">keymap.toml</a></li>
<li><code>~/.config/yazi/</code><a href="https://github.com/sxyazi/yazi/blob/shipped/yazi-config/preset/yazi-default.toml">yazi.toml</a></li>
</ul>
<h2>Plugins</h2>
<ul>
<li>The <a href="https://github.com/yazi-rs/plugins/tree/main/mactag.yazi">mactag.yazi</a> plugin enables the Mac&#8217;s tagging feature in Yazi</li>
<li>The <a href="https://github.com/yazi-rs/plugins/tree/main/jump-to-char.yazi">jump-to-char.yazi</a> plugin enables an &#8216;f&#8217; command to jump to the next file that starts with a specific character.</li>
</ul>
<h2>Use Yazi as a Tmux popup</h2>
<p>When using <a href="https://christofersandin.com/texts/terminal-tmux">Tmux</a>, you can use Yazi in a &quot;popup&quot;. This means we can bind a shortcut (I have Tmux <code>&lt;Prefix&gt;</code> + <code>Ctrl</code> + <code>y</code> for Yazi), which gives me an easy-to-reach file explorer in all situations.</p>
<p>You can do this in your <code>.tmux.conf</code> file.</p>
<pre><code>bind C-y display-popup \
  -d &quot;#{pane_current_path}&quot; \
  -w 75% \
  -h 75% \
  -E &quot;yazi&quot;
</code></pre>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://itsfoss.com/yazi/">Yazi is the Terminal-based File Manager I Didn&#8217;t Know I Needed</a> by It&#8217;s FOSS</li>
<li><a href="https://www.markpitblado.me/blog/setting-up-the-yazi-file-manager/">Setting up the Yazi file manager</a> by Mark Pitblado</li>
<li><a href="https://github.com/AnirudhG07/awesome-yazi">awesome-yazi</a> – a curated list of Yazi plugins, flavors, and themes</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: Manage Dotfiles with Stow</title>
        <link>https://christofersandin.com/texts/terminal-stow</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-stow</guid>
        <pubDate>Sun, 27 Apr 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>If you have started reading this introduction, I assume you have a repository with your config files somewhere. Otherwise, I can&#039;t figure out what piqued your interest. Since people spend years tweaking, personalizing, and modifying them to adapt to their preferred way of working, you might as well…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>If you have started reading this introduction, I assume you have a repository with your config files somewhere. Otherwise, I can&#8217;t figure out what piqued your interest. Since people spend years tweaking, personalizing, and modifying them to adapt to their preferred way of working, you might as well manage them with the same skill. Meet Stow.</strong></p>
</div>
<p>Install <em><a href="https://www.gnu.org/software/stow/">Stow</a></em> via <code>brew install stow</code> and then clone that repo into <code>~/dotfiles</code>. The main idea is to use Stow to create symbolic links from these files into your home directory. You could create the symlinks by hand, but Stow automates it.</p>
<p>Here is my current setup:</p>
<pre><code class="language-shell">~/dotfiles (main*) » tree
.
├── aerospace
├── btop
├── editorconfig
├── eslint
├── eza
├── glow
├── helix
├── ideavim
├── neofetch
├── npm
├── nvim
├── prettier
├── README.md
├── stylelint
├── tmux
├── vim
├── wezterm
├── wtf
├── yazi
└── zsh

</code></pre>
<p>Here&#8217;s how my directory setup looks for <code>~/dotfiles/nvim</code> and how I organized the folder structure under that folder to mimic where I want the files to end up in my home directory.</p>
<p>(You can imagine that the first folder <code>~/dotfiles/nvim</code>, which represents the application&#8217;s name, also symbolizes the <code>~</code> directory when placing files.)</p>
<pre><code>~/dotfiles (main*) » tree -a nvim
nvim
└── .config
    └── nvim
        ├── init.lua
        ├── lazy-lock.json
        └── lua
            ├── .luarc.json
            ├── keymaps.lua
            ├── options.lua
            ├── plugins
            │   ├── alpha.lua
            │   ├── auto-indent.lua
            │   ├── colors.lua
            │   ├── comments.lua
            │   ├── completions.lua
            │   ├── formatting.lua
            │   ├── git.lua
            │   ├── linting.lua
            │   ├── lsp-config.lua
            │   ├── lualine.lua
            │   ├── markdown.lua
            │   ├── neo-tree.lua.NOT-IN-USE
            │   ├── noice.lua
            │   ├── none-ls.lua.NOT-IN-USE
            │   ├── nvim-tmux-navigation.lua
            │   ├── oil.lua
            │   ├── telescope.lua
            │   ├── theme.lua
            │   ├── treesitter-textobjects.lua
            │   ├── treesitter.lua
            │   └── which-key.lua
            └── plugins.lua
</code></pre>
<p>Then, use <code>stow</code> to symlink files into <code>~</code> with <code>stow nvim</code></p>
<p>To verify, let&#8217;s look at how the file system looks after this. Running <code>tree -a .config/nvim</code> gives us the <a href="https://formulae.brew.sh/formula/tree">tree structure of the directory</a>:</p>
<pre><code class="language-shell">~ » tree -a .config/nvim
.config/nvim
├── init.lua
├── lazy-lock.json
└── lua
    ├── .luarc.json
    ├── keymaps.lua
    ├── options.lua
    ├── plugins
    │   ├── alpha.lua
    │   ├── auto-indent.lua
    │   ├── colors.lua
    │   ├── comments.lua
    │   ├── completions.lua
    │   ├── formatting.lua
    │   ├── git.lua
    │   ├── linting.lua
    │   ├── lsp-config.lua
    │   ├── lualine.lua
    │   ├── markdown.lua
    │   ├── neo-tree.lua.NOT-IN-USE
    │   ├── noice.lua
    │   ├── none-ls.lua.NOT-IN-USE
    │   ├── nvim-tmux-navigation.lua
    │   ├── oil.lua
    │   ├── telescope.lua
    │   ├── theme.lua
    │   ├── treesitter-textobjects.lua
    │   ├── treesitter.lua
    │   └── which-key.lua
    └── plugins.lua
</code></pre>
<p>Then, pick and choose which ones you like. Stow uses the same name as the folders you have in your repository:</p>
<ul>
<li><code>stow zsh</code></li>
<li><code>stow nvim</code></li>
<li><code>stow wezterm</code></li>
<li>&#8230;</li>
</ul>
<p>This works well for me, and I do not have any more requirements for a solution like this. However, there are other, more complex solutions to the same problem, so feel free to explore other options if this seems a bit rudimentary for your taste.</p>
<hr />
<h2>References</h2>
<ul>
<li><a href="https://www.gnu.org/software/stow/">GNU Stow</a></li>
<li><a href="https://youtu.be/NoFiYOqnC4o?si=aIsCZNxGOM4o418I">Never lose dotfiles again with GNU Stow</a></li>
<li><a href="https://www.youtube.com/watch?v=y6XCebnB9gs">Stow has forever changed the way I manage my dotfiles</a></li>
<li><a href="https://brandon.invergo.net/news/2012-05-26-using-gnu-stow-to-manage-your-dotfiles.html">Using GNU Stow to manage your dotfiles</a> by Brandon Invergo – the post that popularized the technique</li>
<li><a href="https://systemcrafters.net/managing-your-dotfiles/using-gnu-stow/">Using GNU Stow to Manage Symbolic Links for Your Dotfiles</a> by System Crafters</li>
<li><a href="https://venthur.de/2021-12-19-managing-dotfiles-with-stow.html">Managing dotfiles with GNU Stow</a> by Bastian Venthur</li>
<li><a href="https://dotfiles.github.io/">GitHub does dotfiles</a> – tutorials, utilities, and example repos</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Terminal: Tmux</title>
        <link>https://christofersandin.com/texts/terminal-tmux</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/terminal-tmux</guid>
        <pubDate>Thu, 17 Apr 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Terminal Treats</category>
        
        <description>A way to standardize the window and session management inside the terminal. tmux is a terminal multiplexer. It lets you switch easily between several programs in one terminal, detach them (they keep running in the background) and reattach them to a different terminal. I&#039;m relatively new to using…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>A way to standardize the window and session management inside the terminal.</strong></p>
</div>
<blockquote>
<p>tmux is a terminal multiplexer. It lets you switch easily between several programs in one terminal, detach them (they<br />
keep running in the background) and reattach them to a different terminal.</p>
</blockquote>
<p>I&#8217;m relatively new to using <a href="https://github.com/tmux/tmux/wiki">Tmux</a> in my terminal sessions, since the main argument<br />
used to be that you can reconnect to all of the servers you work on from different machines. That was a use case that<br />
didn&#8217;t resonate with me since I spend most of my time on my machine.</p>
<p>However, when digging into <em>Neovim</em>, I came across a few Tmux tutorials too, and started to see another point. With the<br />
help of a little program like <a href="https://github.com/jimeh/tmuxifier">Tmuxifier</a>, I can configure the layouts I need for work<br />
once and then attach to them whenever I switch contexts. This makes the startup time close to zero and has made my<br />
life easier.</p>
<p>I also like that I can jump around between terminal emulators like <a href="https://iterm2.com/">iTerm2</a>,<br />
<a href="https://ghostty.org/">Ghostty</a>, and <a href="https://wezterm.org/">Wezterm</a> and have the same setup in all of them.</p>
<p>After a <code>brew install tmux</code> we can:</p>
<ul>
<li><code>tmux</code> - start</li>
<li><code>tmux ls</code> - show sessions</li>
<li><code>tmux attach</code> - attach to old session</li>
<li><code>tmux attach -t name</code> - attach to <code>name</code> session</li>
</ul>
<p>The default prefix in tmux is <code>Ctrl</code> + <code>B</code>. To see all commands, hit the prefix and <code>:</code> and use the command <code>list-keys</code>.<br />
Another option is to list all commands with the <code>list-commands</code> command.</p>
<h2>Working with Sessions, Windows, and Panes inside tmux</h2>
<p>Here is an overview of how you can think of sessions, windows, and panes in Tmux.</p>
<pre><code class="language-shell">┌────────────────────────────────────────────────────┐   ┌────────────────────────────────────────────────────┐   ┌────────────────────────────────────────────────────┐
│                     Session #1                     │   │                     Session #2                     │   │                     Session #3                     │
│ ┌────────────────────────────────────────────────┐ │   │ ┌────────────────────────────────────────────────┐ │   │ ┌────────────────────────────────────────────────┐ │
│ │                   Window #1                    │ │   │ │                   Window #1                    │ │   │ │                   Window #1                    │ │
│ │ ┌─────────────────────┐┌─────────────────────┐ │ │   │ │                                                │ │   │ │                                                │ │
│ │ │                     ││                     │ │ │   │ │                                                │ │   │ │                                                │ │
│ │ │                     ││                     │ │ │   │ │                                                │ │   │ │                                                │ │
│ │ │       Pane #1       ││       Pane #2       │ │ │   │ │                                                │ │   │ │                                                │ │
│ │ │                     ││                     │ │ │   │ │                                                │ │   │ │                                                │ │
│ │ │                     ││                     │ │ │   │ │                                                │ │   │ │                                                │ │
│ │ └─────────────────────┘└─────────────────────┘ │ │   │ │                                                │ │   │ │                                                │ │
│ └────────────────────────────────────────────────┘ │   │ └────────────────────────────────────────────────┘ │   │ └────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────┐ │   └────────────────────────────────────────────────────┘   │ ┌────────────────────────────────────────────────┐ │
│ │                   Window #2                    │ │                                                            │ │                   Window #2                    │ │
│ │                                                │ │                                                            │ │ ┌────────────────────────────────────────────┐ │ │
│ │                                                │ │                                                            │ │ │                  Pane #1                   │ │ │
│ │                                                │ │                                                            │ │ │                                            │ │ │
│ │                                                │ │                                                            │ │ └────────────────────────────────────────────┘ │ │
│ │                                                │ │                                                            │ │ ┌────────────────────────────────────────────┐ │ │
│ │                                                │ │                                                            │ │ │                  Pane #2                   │ │ │
│ │                                                │ │                                                            │ │ └────────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────┘ │                                                            │ └────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────┘                                                            └────────────────────────────────────────────────────┘

</code></pre>
<h3>Sessions</h3>
<ul>
<li>List sessions: <code>&lt;Prefix&gt; s</code></li>
<li>Rename session: <code>&lt;Prefix&gt; $</code></li>
<li>Destroy a session: <code>&lt;Prefix&gt; :kill-session</code></li>
</ul>
<h3>Windows</h3>
<ul>
<li>List windows: <code>&lt;Prefix&gt; w</code></li>
<li>Create window: <code>&lt;Prefix&gt; c</code></li>
<li>Next window: <code>&lt;Prefix&gt; n</code></li>
<li>Previous window: <code>&lt;Prefix&gt; p</code></li>
<li>Rename current window: <code>&lt;Prefix&gt; ,</code></li>
<li>Select window by number: <code>&lt;Prefix&gt; 0-9</code></li>
</ul>
<h3>Panes</h3>
<ul>
<li>Navigate panes: <code>&lt;Option&gt; &lt;Left&gt;/&lt;Right&gt;/&lt;Up&gt;/&lt;Down&gt;</code></li>
<li>Split horizontal: <code>&lt;Prefix&gt; -</code></li>
<li>Split vertical: <code>&lt;Prefix&gt; |</code></li>
</ul>
<hr />
<h2>Config file</h2>
<p>Located in <code>~/.tmux.conf</code></p>
<pre><code class="language-sh"># ---- Options ---------------------------------------------------------------

# Set color mode
set-option -g default-terminal &quot;tmux-256color&quot;
set-option -ag terminal-overrides &quot;,xterm-256color:RGB&quot;
set-option -g allow-passthrough on
set-option -ga update-environment TERM
set-option -ga update-environment TERM_PROGRAM

# Add mouse support (and do not exit copy mode when dragging with the mouse)
set-option -g mouse on
unbind -T copy-mode-vi MouseDragEnd1Pane

# Display the status bar at the top of the screen
set-option -g status-position top

# Remove delay for exiting insert mode with ESC in Neovim
set-option -sg escape-time 0

# Start windows and panes at 1, not 0
set-option -g base-index 1
set-option -g pane-base-index 1
set-window-option -g pane-base-index 1
set-option -g renumber-windows on

# Set vi mode
set-window-option -g mode-keys vi


# ---- Key maps --------------------------------------------------------------

# Reload config
unbind r
bind r source-file ~/.tmux.conf

# Set prefix to Ctrl-Space
unbind C-b
set-option -g prefix C-Space
bind C-Space send-prefix

# Kill sessions with Ctrl-q
bind -n C-q kill-session

# Split windows open pane in same path as current window
unbind %
bind | split-window -h -c &quot;#{pane_current_path}&quot;
unbind '&quot;'
bind - split-window -v -c &quot;#{pane_current_path}&quot;

# Resize panes
bind j resize-pane -D 5
bind k resize-pane -U 5
bind l resize-pane -R 10
bind h resize-pane -L 10

# Use prefix + m to maximize pane
bind -r m resize-pane -Z

# Use Alt + Arrow keys without prefix key to switch panes
bind -n M-Left select-pane -L
bind -n M-Right select-pane -R
bind -n M-Up select-pane -U
bind -n M-Down select-pane -D

# Shift arrow to switch windows
bind -n S-Left  previous-window
bind -n S-Right next-window

# Keybindings for vi
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
bind-key -T copy-mode-vi 'v' send -X begin-selection # start selecting text with &quot;v&quot;
bind-key -T copy-mode-vi 'y' send -X copy-selection # copy text with &quot;y&quot;


# ---- Styling ---------------------------------------------------------------

# Basic colors of the Statusbar
set-option -g status-style bg=default,fg=black

# Show the window list centered between the left and the right section
set-option -g status-justify absolute-centre

# Style and set contents on the left section
set-option -g status-left &quot;\
#[bg=default,fg=darkgrey]// \
#[bg=default,fg=brightblue]#S \
#[bg=default,fg=darkgrey]// \
&quot;

# Style and set contents on the right section
set-option -g status-right &quot;\
#[bg=default,fg=darkgrey] // \
#[bg=default,fg=brightblue]tmux\
#[bg=default,fg=darkgrey] // \
&quot;
#
# Set max length of left and right section
set-option -g status-left-length 100
set-option -g status-right-length 100

# Style and set content for the inactive windows
set-option -g window-status-format &quot;  \
#I\
#[fg=black]:\
#[fg=darkgrey]#W  \
&quot;

# Style and set content for the active windows
set-option -g window-status-current-format &quot;\
#[bg=default, fg=brightblue]░ #I\
#[fg=brightblue]:\
#[fg=brightblue]#W \
#[fg=default] \
&quot;

# Panes
set-option -g pane-border-style 'fg=black'
set-option -g pane-active-border-style 'fg=brightyellow'


# ---- Load Tmux Plugin Manager and the plugins ------------------------------

# Plugin manager
set-option -g @plugin 'tmux-plugins/tpm'

# List of tmux plugins
set-option -g @plugin 'christoomey/vim-tmux-navigator'

# Initialize Tmux Plugin Manager (keep this at the very bottom of tmux.conf)
run '~/.tmux/plugins/tpm/tpm'
</code></pre>
<hr />
<h2>References</h2>
<h3><strong>Config files</strong></h3>
<ul>
<li><a href="https://github.com/dreamsofcode-io/tmux/blob/main/tmux.conf">.tmux.conf</a> by Dreams of Code</li>
</ul>
<h3>YouTube</h3>
<ul>
<li><a href="https://www.youtube.com/watch?v=DzNmUNvnB04&amp;t=2s">Tmux has forever changed the way I write code</a> by Dreams of Code</li>
<li><a href="https://youtu.be/niuOc02Rvrc?si=uJyYE9WdfhjBs0gp">Tmux will skyrocket your productivity - here’s how</a> by typecraft</li>
<li><a href="https://youtu.be/jaI3Hcw-ZaA?si=MacWaIT1wbhPy34k">Making Tmux better and beautiful - here’s how</a> by typecraft</li>
<li><a href="https://youtu.be/U-omALWIBos?si=zSTINo9iecRUkMxo">How I use Tmux with Neovim for an awesome dev workflow on my Mac</a><br />
by Josean Martinez</li>
</ul>
<h3>Lists</h3>
<ul>
<li><a href="https://github.com/rothgar/awesome-tmux">Awesome Tmux</a></li>
</ul>
<h3>Guides</h3>
<ul>
<li><a href="https://hamvocke.com/blog/a-guide-to-customizing-your-tmux-conf/">Make tmux Pretty and Usable</a> by Ham Vocke – a <code>.tmux.conf</code> walkthrough, line by line</li>
<li><a href="https://tao-of-tmux.readthedocs.io/en/latest/">The Tao of tmux</a> by Tony Narlock – a free book for when you outgrow the intros</li>
<li><a href="https://www.joshmedeski.com/posts/smart-tmux-sessions-with-sesh/">Smart tmux sessions with sesh</a> by Josh Medeski – session management with zoxide and fzf</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>A Certain Size of Companies</title>
        <link>https://christofersandin.com/texts/a-certain-size-of-companies</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/a-certain-size-of-companies</guid>
        <pubDate>Sun, 09 Feb 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Work</category>
        
        <description>Working with smaller companies instead of the big ones always interests me. As my day job is running a small design and technology company, I believe that most smaller companies have a little bit more heart in the game, and that is something I like. I’m not talking about the random one-person…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>Working with smaller companies instead of the big ones always interests me. As my day job is running a small design and technology company, I believe that most smaller companies have a little bit more heart in the game, and that is something I like.</strong></p>
</div>
<p>I’m not talking about the random one-person company that has been active for a week or two, but solid smaller companies with a handful of people with a respectable history of being around for a while.</p>
<ul>
<li><a href="https://usefathom.com/ref/N14IEW">Fathom Analytics</a></li>
<li><a href="https://postmarkapp.com">Postmark</a> </li>
<li><a href="https://craftcms.com">Craft CMS</a></li>
<li><a href="https://statamic.com/">Statamic</a></li>
<li><a href="https://www.getharvest.com/">Harvest</a></li>
<li><a href="https://basecamp.com/">Basecamp</a></li>
<li><a href="https://missiveapp.com/?ref_id=F3E205973E16">Missive</a></li>
</ul>
<p>We also use services from large companies at work. The full disclosure is that we are currently using Slack. Slack is no longer a small company (but it was way smaller when we started using it), and we use Google&#8217;s paid service for email and calendars.</p>
<h2>Tools</h2>
<p><a href="https://usefathom.com/ref/N14IEW">Fathom Analytics</a> is a privacy-focused alternative to Google Analytics. It was created by a team of two developers in Canada (but I&#8217;m pretty sure one is British). Their main goal is to provide website owners with accurate and actionable data about their visitors without compromising privacy.</p>
<p><a href="https://postmarkapp.com">Postmark</a> is a delivery service for transactional and broadcast emails, such as password resets, account notifications, and purchase confirmations. It strongly emphasizes reliability, speed, and security. (Postmark was recently acquired by ActiveCampaign but has managed to maintain its quality so far.)</p>
<h2>Content Management Systems</h2>
<p><a href="https://craftcms.com">Craft</a> is a Content Management System (CMS) known for its flexibility and ease of use. It is a tool that helps designers and developers create custom websites quickly and efficiently. Many small- to medium-sized businesses use Craft to manage their online content, but quite a few large brands also use Craft.</p>
<p>Another CMS we like is <a href="https://statamic.com/">Statamic</a>, which is made by a small team and built upon Laravel. It has a great Control Panel for clients who work in it, and we use it for sites where we don&#8217;t need a database since it allows us to store everything as files.</p>
<h2>Project and time management</h2>
<p>We have tracked time with <a href="https://www.getharvest.com/">Harvest</a> since 2008. It&#8217;s easy to use, summarizes all hours spent on projects at the end of the month, and keeps us informed about where we spend our time. It does this well and gets out of your way.</p>
<p>Project management software comes and goes, but we&#8217;ve stuck with <a href="https://basecamp.com/">Basecamp</a> over the years.</p>
<ul>
<li>Is it the perfect solution? Nope.</li>
<li>Is it the best alternative for software development? Nope.</li>
<li>Is it the most beautifully designed software? Nope.</li>
<li>Does it solve most problems for us and our clients? Yes.</li>
</ul>
<p>It&#8217;s software made for most people, meaning it can be used by clients, partners, CEOs, designers, support staff, project managers, developers, and almost anyone else.</p>
<h2>E-mail</h2>
<p><a href="https://missiveapp.com/?ref_id=F3E205973E16">Missive</a> is an email application made for teams. We utilize the Google Workspace email setup within Missive. Some of our favorite features include having separate and shared accounts in the same app, assigning emails, and discussing them in the app before replying and sending them.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://signalvnoise.com/reconsider/">RECONSIDER</a> by DHH – the classic case for profitable, human-scale software companies</li>
<li><a href="https://benhoyt.com/writings/the-small-web-is-beautiful/">The Small Web is Beautiful</a> by Ben Hoyt</li>
<li><a href="https://ar.al/2020/08/07/what-is-the-small-web/">What is the Small Web?</a> by Aral Balkan</li>
<li><a href="https://robwalling.com/">Rob Walling</a> and <cite><a href="https://saasplaybook.com/">The SaaS Playbook</a></cite> – on building small, sustainable software businesses</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Meet Raycast, My Digital Sidekick</title>
        <link>https://christofersandin.com/texts/meet-raycast-my-digital-sidekick</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/meet-raycast-my-digital-sidekick</guid>
        <pubDate>Sun, 26 Jan 2025 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Tips</category>
        
        <description>For me, it started with an app called Quicksilver. After a while, Apple took that idea and made Spotlight, but Spotlight worked differently. Then I found Alfred – it did the same thing as Quicksilver but also so much more. Alfred is great, but my new sidekick is Raycast. Speed is the most…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>For me, it started with an app called <a href="https://qsapp.com/">Quicksilver</a>. After a while, Apple took that idea and made <em>Spotlight</em>, but Spotlight worked differently.</strong></p>
</div>
<p>Then I found <a href="https://www.alfredapp.com/">Alfred</a> – it did the same thing as Quicksilver but also so much more.</p>
<p>Alfred is great, but my new sidekick is <a href="https://www.raycast.com">Raycast</a>. Speed is the most significant difference, or at least perceived speed. I don&#8217;t have any numbers to go by.</p>
<p>Raycast makes routine tasks quicker. A tool like this is a must for someone who gets a minor panic attack when watching people move their windows around with the mouse and then drag them into misaligned windows on top of each other.</p>
<p>With no further explanation, the plugins I use every day:</p>
<ul>
<li>Application launcher</li>
<li><a href="https://www.raycast.com/extensions/calendar">My Schedule</a></li>
<li><a href="https://www.raycast.com/extensions/window-management">Window management</a> (combined with <em>AeroSpace</em>)</li>
<li><a href="https://www.raycast.com/extensions/snippets">Snippets</a></li>
<li><a href="https://www.raycast.com/extensions/clipboard-history">Clipboard History</a></li>
<li><a href="https://manual.raycast.com/hotkey">Hotkeys</a></li>
</ul>
<p>Plugins I use once in a while:</p>
<ul>
<li><a href="https://www.raycast.com/mattisssa/spotify-player">Spotify Player</a></li>
</ul>
<p>There, use your keyboard.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://manual.raycast.com/">Raycast Manual</a> – the official documentation for snippets, clipboard history, window management, and hotkeys</li>
<li><a href="https://michalkuncio.com/the-ultimate-guide-to-raycast-productivity-for-developers/">The Ultimate Guide to Raycast Productivity for Developers</a> by Michał Kuncio</li>
<li><a href="https://nikitabobko.github.io/AeroSpace/guide">AeroSpace Guide</a> – the tiling window manager mentioned above</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Starting in Our Field</title>
        <link>https://christofersandin.com/texts/starting-in-our-field</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/starting-in-our-field</guid>
        <pubDate>Thu, 01 Aug 2024 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Work</category>
        
        <description>I’m getting older, but at the same time, I’m starting to pick up quite a bit of experience from running a business for almost 20 years. I started with my firm, freelancing, and taking on small projects while at university. Over the last 15 years, I’ve been running a small development and design…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>I’m getting older, but at the same time, I’m starting to pick up quite a bit of experience from running a business for almost 20 years. I started with my firm, freelancing, and taking on small projects while at university. Over the last 15 years, I’ve been running a small development and design company, working with clients of all sizes.</strong></p>
</div>
<p>One of the most common questions when meeting students looking for internships or people starting in our line of work is, “What should I learn?” That is a good question, of course, but I think many people give bad advice.</p>
<p>Whether you are a talented developer or an aspiring designer, I <strong>recommend starting with the basics</strong>.</p>
<p>By that, I mean the technologies that may seem a little too simple to you, but still dominate the internet to a large extent. I’m talking about <a href="https://en.wikipedia.org/wiki/HTML"><strong>HTML</strong></a>, <a href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets"><strong>CSS</strong></a>, and <a href="https://en.wikipedia.org/wiki/JavaScript"><strong>JavaScript</strong></a>. One step up from protocols and requests, these are the three fundamental elements that enable every web page, every web app, and all custom-designed systems on the internet to function.</p>
<p>Make sure you understand the basics unique to the web, such as how content flows on different screen sizes, zooming in and out, and other related concepts, before jumping in and trying to learn <a href="https://facebook.github.io/react/">React</a>.</p>
<h2>Long live HTML</h2>
<p>All server-side programming languages ultimately result in HTML that the user can view, browse, and interact with.</p>
<p>Even if you are going to spend most of your time in <a href="http://www.phptherightway.com/">PHP</a>, <a href="https://www.python.org">Python</a>, or <a href="https://dotnet.microsoft.com/en-us/">Microsoft’s .net</a>, <strong>you still need to understand the result you produce</strong>. I’ve met far too many developers with five or more years of experience working with the web who are still not clear about how to write simple markup or CSS rules. Don&#8217;t be that person.</p>
<p>There are countless HTML frameworks, even more CSS frameworks, and a <a href="https://www.google.se/search?q=javascript+framework">million JavaScript frameworks</a> to look at. Add a task runner like <em>Gulp</em>, or a tool like <em>Vite</em>, and you start complicating it even more for your first project. And I won&#8217;t even mention <em>Webpack</em>…</p>
<h2>The foundation</h2>
<p>However, after spending time looking at and understanding the basics, it doesn’t matter if the site uses <a href="http://getbootstrap.com/">Bootstrap</a> or <a href="http://foundation.zurb.com/">Foundation</a> since you know CSS.</p>
<ul>
<li>Take some time to understand semantic HTML and how to mark up content.</li>
<li>Take the time to examine CSS and understand both the selectors and the cascade.</li>
<li>Experiment with native JavaScript to gain a deeper understanding of the language.</li>
</ul>
<p>After that, you’ll be much more efficient and employable, and can pick up Bootstrap, Vue, or React in a few hours if needed.</p>
<p><em>To be clear, I’m not saying “don’t use frameworks”;</em> I’m just saying start by learning the basics before you do, and then make an educated choice when choosing the one(s) to use.</p>
<p>By the way, learning to write good HTML and utilize styles and scripts effectively also helps you create more accessible content, making it <strong>easier for search engines to index your content</strong>.</p>
<p>Customers pay for that, which is a good start if you want to make a living working in this field.</p>
<p>And have fun. Learning new things is great, but you don’t have to know all the new things all the time. That is another common misconception about how the web works.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://rachelandrew.co.uk/archives/2019/01/30/html-css-and-our-vanishing-industry-entry-points/">HTML, CSS and our vanishing industry entry points</a> by Rachel Andrew</li>
<li><a href="https://developer.mozilla.org/en-US/curriculum/">MDN Curriculum</a> – fundamentals first, frameworks as optional extensions</li>
<li><a href="https://www.theodinproject.com/">The Odin Project</a> – a free curriculum that teaches HTML, CSS, and vanilla JavaScript before any framework</li>
<li><a href="https://web.dev/learn/css">Learn CSS</a> and <a href="https://web.dev/learn/design/">Learn Responsive Design</a> by web.dev</li>
<li><a href="https://javascript.info/">The Modern JavaScript Tutorial</a></li>
<li><a href="https://vanillajstoolkit.com">The Vanilla JS Toolkit</a> by Chris Ferdinandi</li>
<li><a href="https://plainvanillaweb.com/index.html">Plain Vanilla</a> – web development without frameworks</li>
<li><a href="https://localghost.dev/blog/the-right-tag-for-the-job-why-you-should-use-semantic-html/">The right tag for the job: why you should use semantic HTML</a> by Sophie Koonin</li>
<li><a href="https://frontendmasters.com/guides/front-end-handbook/2024/">The Front End Developer/Engineer Handbook</a> by Frontend Masters</li>
<li><cite><a href="https://resilientwebdesign.com">Resilient Web Design</a></cite> by Jeremy Keith</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>The Forgiving Nature of the Web</title>
        <link>https://christofersandin.com/texts/the-forgiving-nature-of-the-web</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/the-forgiving-nature-of-the-web</guid>
        <pubDate>Wed, 24 Jul 2024 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Work</category>
        
        <description>HTML and CSS are both extraordinarily relaxed and forgiving. If you forget to close a tag or enter incorrect values in a CSS property, it&#039;s not a big deal, as the parsers continue while ignoring the error. However, that does not mean you have to use these traits intentionally because you are lazy.…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>HTML and CSS are both extraordinarily relaxed and forgiving. If you forget to close a tag or enter incorrect values in a CSS property, it&#8217;s not a big deal, as the parsers continue while ignoring the error. However, that does not mean you have to use these traits intentionally because you are lazy.</strong></p>
</div>
<p>When you add JavaScript, it becomes a lot harder. A typo in that code stops execution — nothing after the error runs. But JavaScript is a loosely typed language, so it’s still way more forgiving than the Ada language I was taught at university.</p>
<blockquote>
<p>HTML and CSS are both extraordinarily relaxed and forgiving.</p>
</blockquote>
<p>This does not mean you have to be sloppy and lazy. Fault-tolerant systems are a backup with robustness built in. That is not an excuse to “don&#8217;t bother.”</p>
<p>Sooner or later, you will run into unexpected issues when you try to cut corners. From working in this field for a long time and working with many developers, I can confidently say that if you concern yourself with the details and get it right from the start, you can spend a lot of hours doing something valuable instead of fixing bugs. Trust me, you&#8217;ll have enough of those anyway&#8230;</p>
<p>Think of it this way. It’s nice to know that you can walk with your shoelaces untied. It&#8217;s great that it works, and occasionally, when you forget to tie your shoes, you benefit from that. Still, it&#8217;s a good idea to tie your shoes when you put them on.</p>
<p>Therefore, write strict HTML, lint your CSS, and compile your JavaScript to up your game. Don&#8217;t rely on fault tolerance to fix your code. You win in the long run.</p>
<hr />
<h2>Resources</h2>
<ul>
<li><a href="https://htmlparser.info/">Idiosyncrasies of the HTML parser</a> by Simon Pieters – a free book on how the forgiving error handling was actually specced</li>
<li><a href="https://www.rfc-editor.org/rfc/rfc9413.html">Maintaining Robust Protocols, RFC 9413</a> – the IETF revisiting Postel&#8217;s law: why &quot;be liberal in what you accept&quot; has limits</li>
<li><a href="https://alistapart.com/article/understandingprogressiveenhancement/">Understanding Progressive Enhancement</a> by Aaron Gustafson, <cite>A List Apart</cite></li>
<li><a href="https://www.gov.uk/service-manual/technology/using-progressive-enhancement">Building a robust frontend using progressive enhancement</a> by GOV.UK</li>
<li><cite><a href="https://resilientwebdesign.com">Resilient Web Design</a></cite> by Jeremy Keith</li>
<li><a href="https://meiert.com/en/blog/48-laws-rules-and-principles/">48 Laws, Rules, and Principles of Web Development</a> by Jens Oliver Meiert</li>
</ul>
]]></content:encoded>
    </item>
    
    <item>
        <title>Minimalism</title>
        <link>https://christofersandin.com/texts/minimalism</link>
        <guid isPermaLink="true">https://christofersandin.com/texts/minimalism</guid>
        <pubDate>Mon, 15 Jul 2024 00:00:00 +0000</pubDate>
        <dc:creator>Christofer Sandin</dc:creator>
        
        <category>Mini-essay</category>
        
        <description>Something about minimalism as a theme appeals to me. We have too many things, and striving for the next one all the time hurts us more than we might think. These are not unique ideas, but they resonate with me. I&#039;ve always preferred to buy a few quality items rather than a lot of cheap ones. In…</description>
        <content:encoded><![CDATA[<div class="text--introduction">
<p><strong>Something about minimalism as a theme appeals to me. We have too many things, and striving for the next one all the time hurts us more than we might think.</strong></p>
</div>
<p>These are not unique ideas, but they resonate with me. I&#8217;ve always preferred to buy a few quality items rather than a lot of cheap ones. In this day and age, that mindset is becoming increasingly important, and more people are getting on board.</p>
<p>I&#8217;m not a minimalist yet, but there are some interesting ideas in the articles below. These ideas apply to both my physical space, where I live, and the digital space where I work. The word associated with this is &quot;uncluttering,&quot; and I think it makes sense.</p>
<p>The first thing I did years ago, without striving for a more minimalistic approach, was to eliminate most of the alerts and notifications on my phone. I felt more disturbed and unfocused each day when something beeped and blinked for attention every 40 seconds—getting rid of those made my days calmer.</p>
<p>Start the journey by disabling notifications on your phone and computer, and start making informed purchase decisions. That&#8217;s where I am at the moment, and baby steps are better than no steps at all.</p>
<hr />
<h2>Explore minimalism on your own</h2>
<ul>
<li><a href="https://hbr.org/2019/03/the-case-for-finally-cleaning-your-desk">The Case for Finally Cleaning Your Desk</a></li>
<li><a href="https://www.theminimalists.com/aditl/">A Day in the Life of a Minimalist</a></li>
<li><a href="https://projecthotmess.com/habits-of-minimalist-living/">11 Habits of Minimalist Living You Can Adopt Today</a></li>
<li><a href="https://calnewport.com/on-digital-minimalism/">On Digital Minimalism</a> by Cal Newport</li>
<li><cite><a href="https://wwnorton.com/books/9780393609035">Goodbye, Things: The New Japanese Minimalism</a></cite> by Fumio Sasaki</li>
<li><a href="https://news.utexas.edu/2017/06/26/the-mere-presence-of-your-smartphone-reduces-brain-power/">The Mere Presence of Your Smartphone Reduces Brain Power</a> – the &quot;brain drain&quot; study from UT Austin</li>
</ul>
]]></content:encoded>
    </item>
    
</channel>
</rss>
