eheidi.devA personal blog about technology, 3D printing, technical writing, and some gaming.https://eheidi.devFreeCAD Tutorial: Create a Multicolor SVG Keychainhttps://eheidi.dev/posts/freecad-multicolor-svg-keychainhttps://eheidi.dev/posts/freecad-multicolor-svg-keychainLearn how to design a multicolor 3D printed keychain from an SVG in FreeCAD using layer height color changes — no multi-material setup needed.Thu, 05 Mar 2026 00:00:00 GMT<p>Have you ever wanted to create a multicolor 3D print from a vector logo? In this tutorial, you'll learn how to use FreeCAD to design a multicolor keychain by working with SVG paths at different layer heights — a technique that allows you to achieve stunning color changes with a single-extrusion printer. We'll use the FreeCAD logo as an example, but the same approach works with any SVG file.</p>
<p>This tutorial covers the <strong>Draft</strong> and <strong>Part Design</strong> workbenches in FreeCAD, and walks you through everything from importing an SVG to slicing the model with color change instructions. Text instructions are included below if you'd prefer to follow along without watching the video.</p>
<p><iframe width="100%" height="540" src="https://www.youtube.com/embed/zoGs2wc85_I" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Step 1: Get a Suitable SVG File</h2>
<p>The first step is to find or prepare an SVG file whose different path elements can serve as separate color layers.</p>
<p>For this tutorial, we'll use the <strong>FreeCAD logo</strong>, which is freely available on Wikipedia:</p>
<ol>
<li>Search for the FreeCAD logo on Wikipedia</li>
<li>Click the download link and select <strong>full resolution</strong></li>
<li>Download the full SVG file to your computer</li>
</ol>
<blockquote>
<p><strong>Tip:</strong> Look for SVG files where different visual areas are represented as separate paths — this makes it much easier to assign different heights per color zone.</p>
</blockquote>
<h2>Step 2: Import the SVG into FreeCAD</h2>
<ol>
<li>Create a <strong>new file</strong> in FreeCAD</li>
<li>Go to <strong>File → Import</strong></li>
<li>Select your SVG file</li>
<li>When prompted, mark the SVG as <strong>geometry</strong> (not as drawing)</li>
<li>Click <strong>Yes</strong> when asked about DPI settings</li>
</ol>
<p>The full logo will appear in the viewport.</p>
<h2>Step 3: Clean Up the SVG Paths</h2>
<p>The imported SVG may include elements you don't need, such as text or surrounding rectangles. Remove these to keep only the paths you'll be working with:</p>
<ol>
<li>Inspect the imported elements in the model tree</li>
<li>Select and <strong>delete</strong> any paths that correspond to text or unwanted areas (e.g., the letters and the surrounding rectangle in the FreeCAD logo)</li>
<li>Keep only the paths that represent the visual areas you want to use as distinct color layers</li>
</ol>
<p>After cleanup, you should have the core logo shape split into its individual paths.</p>
<h2>Step 4: Plan Your Layer Heights</h2>
<p>Before converting paths to sketches, think about which parts will be printed at which height — and in which order. Each path will become a separate pad, and the height difference between pads determines where color changes happen.</p>
<p>For the FreeCAD logo keychain, the layer plan is:</p>
<table>
<thead>
<tr>
<th>Path</th>
<th>Height</th>
<th>Color</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cog (background gear shape)</td>
<td>2 mm</td>
<td>Light blue (first filament)</td>
</tr>
<tr>
<td>Base shape</td>
<td>4 mm</td>
<td>Red</td>
</tr>
<tr>
<td>Path one (border detail)</td>
<td>5 mm</td>
<td>Red (same filament)</td>
</tr>
<tr>
<td>F letter</td>
<td>6 mm</td>
<td>White (last filament)</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>Important:</strong> Work with connected parts together. If two paths are adjacent (touching), convert and pad them in the same session to avoid errors in FreeCAD.</p>
</blockquote>
<h2>Step 5: Convert Paths to Sketches and Combine them in a Body</h2>
<p>For each path, you'll need to convert it from a draft object into a proper sketch, then place it inside a body and pad it.</p>
<h3>5.1 Switch to the Draft Workbench</h3>
<ol>
<li>Switch to the <strong>Draft</strong> workbench</li>
<li>Select the path you want to work with first</li>
</ol>
<h3>5.2 Convert Path to Sketch</h3>
<ol>
<li>Go to <strong>Modification → Draft to Sketch</strong> (or find the button in the toolbar)</li>
<li>FreeCAD will generate a sketch from the selected path</li>
</ol>
<h3>5.3 Create a Body and Add the Sketch</h3>
<ol>
<li>Create a <strong>new Body</strong> if you don't have one yet (Part Design workbench → Create body)</li>
<li><strong>Move the sketch</strong> into the active body (drag it in the model tree)</li>
</ol>
<h3>5.4 Pad the Sketch</h3>
<ol>
<li>With the sketch inside the body, switch to <strong>Part Design</strong></li>
<li>Select the sketch and click <strong>Pad</strong></li>
<li>Set the desired height (e.g., <strong>4 mm</strong> for the base shape)</li>
<li>Click <strong>OK</strong></li>
<li>Hide the original path to keep the workspace clean</li>
</ol>
<p>Repeat this process for each path using the same active body, with the heights defined in your layer plan:</p>
<ul>
<li><strong>Cog path</strong> → 2 mm</li>
<li><strong>Base path</strong> → 4 mm</li>
<li><strong>Path one (border)</strong> → 5 mm</li>
<li><strong>F letter</strong> → 6 mm</li>
</ul>
<h2>Step 6: Add a Keychain Hole</h2>
<p>To turn the model into a keychain, add a small hole:</p>
<ol>
<li>Select the <strong>top face</strong> of the model where you want the hole</li>
<li>Create a <strong>new Sketch</strong> on that face</li>
<li>Use the <strong>Circle tool</strong> to draw a small circle (position it near the top edge)</li>
<li>Close the sketch</li>
<li>Use <strong>Pocket → Through All</strong> to cut the hole completely through the model</li>
</ol>
<h2>Step 7: Export as STL</h2>
<ol>
<li>Select the object in the model tree</li>
<li>Go to <strong>File → Export</strong></li>
<li>Choose <strong>STL Mesh</strong> format</li>
<li>Save the file</li>
</ol>
<h2>Step 8: Slice with Color Changes in Prusa Slicer</h2>
<ol>
<li>Open <strong>Prusa Slicer</strong> and import the exported STL</li>
<li>The model may appear very large — <strong>resize it</strong> (e.g., to 40% of original size) to make a practical keychain</li>
<li>Prusa Slicer may automatically detect color changes. Look for the prompt: <em>"Slicer object looks like a logo or sign — apply color change automatically?"</em> and click <strong>Yes</strong></li>
</ol>
<h3>8.1 Adjust Color Changes</h3>
<p>The automatic detection may add more color changes than you need. To fine-tune:</p>
<ol>
<li>Review the color change markers on the layer slider</li>
<li>Remove any unwanted changes by moving to the layer where the change occurs and clicking the <strong>X</strong> button next to the marker</li>
<li>For this keychain, keep only <strong>two color changes</strong> (three colors total)</li>
</ol>
<h3>8.2 Preview Colors</h3>
<p>You can assign preview colors to each segment to visualize the final result:</p>
<ul>
<li>First color: <strong>Light blue</strong> (cog background)</li>
<li>Second color: <strong>Red</strong> (main logo body)</li>
<li>Third color: <strong>White</strong> (F letter)</li>
</ul>
<h3>8.3 Enable Ironing for a Smooth Finish</h3>
<p>For the best surface quality on the top layers:</p>
<ol>
<li>Go to <strong>Print Settings → Infill</strong></li>
<li>Enable <strong>Ironing</strong> (surface ironing)</li>
<li>This will make the top layers very smooth, similar to the finished keychain shown at the start of the video</li>
</ol>
<blockquote>
<p><strong>Note:</strong> Ironing increases print time (roughly 3×), but the result is a polished, professional-looking surface that's especially effective for logo keychains.</p>
</blockquote>
<h2>Conclusion</h2>
<p>Creating a multicolor keychain from an SVG in FreeCAD is a great way to combine vector design skills with 3D printing. By assigning different pad heights to different SVG paths, you control exactly where color changes happen — no multi-material setup required. Once you've mastered this technique with the FreeCAD logo, try it with your own SVG artwork! Check out more tutorials under the <a href="/tags/3d-printing">3d-printing</a> and <a href="/tags/freecad">freecad</a> tags to keep learning.</p>
Erika HeidiHow I'm Using GitHub Copilot to Streamline Content Publishinghttps://eheidi.dev/posts/how-i-use-github-copilot-for-content-publishinghttps://eheidi.dev/posts/how-i-use-github-copilot-for-content-publishingHow GitHub Copilot and Agentic Workflows are helping me publish blog posts from anywhere — even from my phone at the gym.Tue, 24 Feb 2026 00:00:00 GMT<p>Writing has always been a passion for me, but with everything else going on there is not much time left to sit on my desk, grab a cup of coffee, and just write. Writing became a work activity, not something I feel like doing when I have some free time. But the thinking never stops, and sometimes I feel like I have something valuable to share.</p>
<h2>Writing on the Go</h2>
<p>So one of these days I tried writing on my notes app while I'm on the treadmill, at my gym. That worked surprisingly well, so I used some of my gym sessions to write down LinkedIn posts and random ideas for videos. I also used this time to edit videos from my phone.</p>
<p>Eventually I wrote way too much and ended up finding out that LinkedIn has a character limit for posts. "What a shame", I thought, as I found it difficult to cut down on words and I really wanted to share that piece of content on its entirety.</p>
<p>"What about my blog?", I thought. That would be great, but from the gym I cannot really post anything to my Git-based static blog. Or can I? 🤔</p>
<h2>Copilot to the Rescue</h2>
<p>"Maybe Copilot can help me. I already have the content, after all!" - so it would be only an operational thing: create a pull request on my blog repo including the content I would provide it, and then I could preview, review, and merge the PR directly from the treadmill.</p>
<p>I went to the "Agents" tab of my repo using the GitHub mobile app. My first prompt was:</p>
<blockquote>
<p>Bootstrap a new blog post with the title "Use the Right Tool for the Job and your Skillset" and create a pull request so that I can add the content. Tags: "career", "development"</p>
</blockquote>
<p>Then after a little while I got a notification from an open PR on my repo. The PR had exactly what I asked for: a markdown skeleton I could edit to include my text. I was able to finish the post from my phone, but it was still quite a bit of work. <a href="/posts/use-the-right-tool-for-the-job-and-your-skillset/">This</a> was the first published post.</p>
<p>A couple days later I improved the process and instead of using the "Agents" tab, I created an issue with the content already in a code block, with instructions to create a blog post using that content. The, I assigned the issue to Copilot, and a similar process followed, but this time the PR already contained everything. <a href="/posts/how-being-a-generalist-is-paying-off-in-2026/">This</a> was the result from the <a href="https://github.com/erikaheidi/blog/issues/15">original issue</a>.</p>
<h2>Turning Videos into Quickstart Tutorials</h2>
<p>Another blogging struggle I had was around turning a video tutorial into a text version. Writing a detailed tutorial for things like 3D design software is lot of work, as I'd need to show the interface with screenshots and all. Making a video is much easier, and takes me much less time. But I understand that some people prefer to follow along with a text version. So I picked a video transcript from Google Drive (auto-generated when you upload a video there) and asked Copilot to create a step-by-step summary of the video and include the embed in a blog post. It also generated a short intro and conclusion, which was fine. You can see the result <a href="/posts/freecad-tutorial-penholder/">here</a> and <a href="https://eheidi.dev/posts/freecad-spreadsheets-formulas/">here</a>. I was actually pretty happy with this use case, because I could focus on creating the videos and still make them acessible. Also, I wasn't using any AI to author the original content, so I felt good about that too.</p>
<h2>Migrating to Copilot Agentic Workflows</h2>
<p>I was trying to figure out the best way to handle this automation without having to repeat the same prompt over and over, and that was around the same time I heard about <a href="https://github.github.io/gh-aw/">Copilot Agentic Workflows</a> for the first time.</p>
<p>Luckily for me, as part of the <a href="https://stars.github.com/profiles/erikaheidi/">GitHub Stars</a> program I get to join some meetings with GitHub engineers where they share the latest features and things that are not yet in general availability. Shortly after one of these meetings I started my experiments to create Agentic Workflows with the goal of streamlining my blog publishing process, and here's where I am today: this post was 90% made from my phone while on the gym. Copilot created the PR for me, and I am just finishing the other 10% with some links to demonstrate the process. The best thing is that the "Blog Post Creator" workflow was <strong>also</strong> created by Copilot through the "Agents" tab!</p>
<p>After I got the Blog Post Creator workflow up and running, I set up another workflow to deal with the video tutorials, this time triggered by the label <code>youtube-todo</code>. Instead of creating a PR directly (which would sort of duplicate the process), I asked the agent to prepare the content and create a new issue with the <code>content-todo</code> label, in order to trigger the "Blog Post Creator" workflow. So, basically I:</p>
<ul>
<li>create an issue providing a YouTube URL and the transcript of the video in a code block, label with <code>youtube-todo</code></li>
<li>the "Youtube to Blog Post Creator" workflow starts working on the issue, generates a blog post, then creates a new issue to trigger the "Blog Post Creator" workflow (label <code>content-todo</code> )</li>
<li>the "Blog Post Creator" workflow is triggered and proceeds to create a PR with the new blog post.</li>
</ul>
<p>If the content is just text, I create an issue to trigger the Blog Post Creator workflow directly.</p>
<h3>The Prompt</h3>
<p>The "Blog Post Creator" workflow was created based on the following prompt:</p>
<blockquote>
<p>Create a workflow for GitHub Agentic Workflows using https://raw.githubusercontent.com/github/gh-aw/main/create.md</p>
<p>The purpose of this workflow is to create a PR with a new blog post using information provided in a GitHub issue. The workflow should be triggered when an open issue is labeled with the "content-todo" label. Based on the content provided, create a SEO friendly title and description. Check the tags already used in the blog and tag the post apropriately with a maximum of 3 tags. Do not include any additional content in the body of text.</p>
</blockquote>
<p>Took only a couple minutes to get the PR ready for review with the new workflow. After <a href="#workflow-setup">some tweaking</a>, I got it up and running.</p>
<p>One important thing to notice is that Agentic workflows are actually markdown (.md) files with a YAML frontmatter that defines some metadata, permissions, and rules for triggering the workflow. You'll then run a <code>gh aw compile</code> command (or instruct the agent to do so, when needed) to "compile" the agentic workflow markdown and generate a <strong>lock</strong> file that is the actual workflow that will be executed. That will be a much longer file with several instructions and guardrails in place. For reference, you can have a look at <a href="https://github.com/erikaheidi/blog/blob/main/.github/workflows/create-blog-post.md">the agentic markdown file</a> and its <a href="https://github.com/erikaheidi/blog/blob/main/.github/workflows/create-blog-post.lock.yml">generated lock file</a>.</p>
<h3>Workflow Setup</h3>
<p>To make everything work, I needed to:</p>
<ul>
<li>Update a few settings in the repository to allow GitHub Actions to create new pull requests (Settings -> Actions -> General -> Workflow Permissions, then check the box for "Allow GitHub Actions to create and approve pull requests").</li>
<li>Create a <a href="https://github.github.io/gh-aw/reference/auth/#copilot_github_token">fine-grained PAT (personal access token)</a> to authenticate to Copilot CLI from the workflow.</li>
<li>Update Copilot security settings (Settings -> Copilot -> Agent -> Custom Allowlist) to allow requests to <code>https://api.github.com/repos/github/gh-aw</code>, so that the agent is able to fetch the <code>gh aw</code> extension, which is needed to compile the markdown workflow file and generate the lock file (the actual workflow that you're not supposed to manually change).</li>
</ul>
<h2>Conclusion</h2>
<p>Agentic Workflows are really handy for my use case since I don't have much time to spend on the operational tasks required to get my ideas published here. I can focus on my original content and let Copilot handle the boring and time-consuming tasks without having to explicitly tell him what to do - just create an issue, add the content, and label it appropriately.</p>
<p>If you want to try out Copilot Agentic Workflows, check the excellent <a href="https://github.github.io/gh-aw/setup/creating-workflows/">official docs</a> to get started quickly.</p>
Erika HeidiTurning an SVG into a 3D Printed Object with FreeCADhttps://eheidi.dev/posts/turning-svg-into-3d-object-freecadhttps://eheidi.dev/posts/turning-svg-into-3d-object-freecadLearn how to import an SVG file into FreeCAD, convert it to a sketch, and pad it into a 3D printable model ready for printing.Thu, 19 Feb 2026 00:00:00 GMT<p>Have you ever wanted to turn a simple logo or icon into a physical 3D-printed object? In this tutorial, you'll learn how to import an SVG file into FreeCAD and convert it into a 3D model ready for printing. This is a great technique for creating custom keychains, decorations, or branded items from any vector artwork you have on hand.</p>
<p>We'll use the <strong>Draft</strong>, <strong>Part Design</strong>, and <strong>Sketcher</strong> workbenches in FreeCAD, and the whole process is surprisingly straightforward once you know the steps. Both the video and step-by-step text instructions are provided below so you can follow along whichever way you prefer.</p>
<p><iframe width="100%" height="540" src="https://www.youtube.com/embed/0FWJAbgwDs0" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Step 1: Find or Prepare a Suitable SVG File</h2>
<p>The first step is to choose an appropriate SVG file. Not all SVGs work equally well for this workflow, so keep the following tips in mind:</p>
<ul>
<li><strong>Use a simple, filled shape</strong>: SVGs with closed wires and filled areas are the easiest to work with.</li>
<li><strong>Avoid overly complex paths</strong>: More complex SVGs may require working in layers or handling multiple paths separately.</li>
<li><strong>Empty spaces become pockets</strong>: If your SVG has hollow areas (like letters or cut-out designs), those will become pockets in the final 3D model.</li>
</ul>
<p>A great free resource for SVG files is <a href="https://www.svgrepo.com">SVG Repo</a>, which offers a large collection of free SVG icons. For this tutorial, a simple flower icon is used as an example.</p>
<p>:::tip
If you are designing your own SVG, it is recommended to use <strong>Inkscape</strong> to ensure compatibility with FreeCAD's import process.
:::</p>
<h2>Step 2: Import the SVG as Geometry in FreeCAD</h2>
<p>With your SVG file ready, open FreeCAD and import it:</p>
<ol>
<li>Go to <strong>File → Import</strong>.</li>
<li>Select your SVG file.</li>
<li>A dialogue will appear asking how to open the file. Choose <strong>"SVG as geometry"</strong> — NOT "image formats".
<ul>
<li>"Image formats" imports it as a flat picture for tracing over; "SVG as geometry" imports the actual paths so you can work with them directly.</li>
</ul>
</li>
<li>Click <strong>OK</strong>. FreeCAD may warn that the file was not created with Inkscape — this is fine, just click OK to dismiss the warning.</li>
</ol>
<p>You should now see the raw lines/paths of your SVG in the 3D viewport.</p>
<h2>Step 3: Convert the Paths to a Sketch Using the Draft Workbench</h2>
<p>The imported SVG consists of draft paths, which cannot be padded directly into a 3D object. You need to convert them into a sketch first:</p>
<ol>
<li>Switch to the <strong>Draft workbench</strong>.</li>
<li>Select all the paths that make up your SVG shape (hold Shift or Ctrl to select multiple).</li>
<li>Click the <strong>"Draft to Sketch"</strong> button in the toolbar (it converts draft objects into a Sketcher sketch).</li>
<li>You should now see a new <strong>Sketch</strong> object appear in the model tree on the left sidebar.</li>
<li>Hide the original draft paths by selecting them and pressing the <strong>Space bar</strong> — this keeps your workspace clean.</li>
</ol>
<h2>Step 4: Set Up the Part Design Workbench and Move the Sketch into a Body</h2>
<p>FreeCAD's Part Design workbench requires geometry to be inside an active <strong>Body</strong>. Since the imported sketch was created outside of one, you need to move it:</p>
<ol>
<li>Switch to the <strong>Part Design workbench</strong>.</li>
<li>Create a new <strong>Body</strong> by clicking the "Create body" button.</li>
<li>In the model tree, click and drag the <strong>Sketch</strong> into the new Body (or right-click and use the move option).</li>
<li>The sketch must be inside the body to work with Part Design tools.</li>
</ol>
<p>If you open the sketch, you'll see all the paths exactly as they appeared in the original SVG file.</p>
<p>:::note
There is no need to fully constrain this sketch unless you are working on something that requires precision. For a simple decoration or keychain, leaving it unconstrained is perfectly fine.
:::</p>
<h2>Step 5: Pad the Sketch into a 3D Object</h2>
<p>Now comes the fun part — turning the flat sketch into a 3D shape:</p>
<ol>
<li>Select the <strong>Sketch</strong> in the model tree.</li>
<li>Click the <strong>Pad</strong> tool.</li>
<li>Set a pad height — for example, <strong>10 mm (1 cm)</strong> is a good starting point.</li>
<li>Click <strong>OK</strong>.</li>
</ol>
<p>Your SVG is now a 3D solid object! Don't worry too much about the exact dimensions here, because the SVG may import at a very large scale. You can easily <strong>resize the model in your slicer software</strong> (like PrusaSlicer or Bambu Studio) rather than adjusting the sketch in FreeCAD.</p>
<h2>Step 6: (Optional) Add a Hole for a Keychain</h2>
<p>If you want to turn your model into a keychain, you can add a hole through the top of the object:</p>
<ol>
<li>Click on the <strong>top face</strong> of your padded model to select it.</li>
<li>Create a <strong>new Sketch</strong> on that face.</li>
<li>Draw a small <strong>circle</strong> where you'd like the keychain hole to go.</li>
<li>Close the sketch.</li>
<li>Select the <strong>Pocket</strong> tool.</li>
<li>Choose <strong>"Through All"</strong> as the type so the hole goes completely through the object.</li>
<li>Click <strong>OK</strong>.</li>
</ol>
<p>You now have a hole you can thread a keychain ring through!</p>
<h2>Step 7: Export the Model as an STL File</h2>
<p>To prepare the model for 3D printing:</p>
<ol>
<li>Make sure your model (body/object) is selected in the model tree.</li>
<li>Go to <strong>File → Export</strong>.</li>
<li>Enter a filename and select <strong>STL Mesh</strong> as the file format.</li>
<li>Click <strong>OK</strong> to save the file.</li>
</ol>
<h2>Step 8: Slice and Print</h2>
<p>Import the STL file into your slicer software of choice:</p>
<ol>
<li>Open your slicer (e.g., PrusaSlicer, Bambu Studio, Cura).</li>
<li>Import the STL file — it will likely appear very large.</li>
<li><strong>Resize the model</strong> to a suitable size. For a keychain, reducing it to <strong>50% or less</strong> of the original is often a good starting point.</li>
<li>Adjust print settings as needed.</li>
<li>Slice the model and send it to your printer.</li>
</ol>
<h2>Conclusion</h2>
<p>Turning an SVG into a 3D printable model in FreeCAD is a remarkably quick and accessible workflow once you know the steps. From importing the SVG as geometry, converting it to a sketch, and padding it into a solid, you can go from a flat vector image to a physical printed object in just a few minutes. This technique opens up a world of possibilities — from custom keychains and badges to branded decorations and beyond. Try it with your own logos or icons and see what you can create!</p>
Erika HeidiFreeCAD Tutorial: Designing a Fully Constrained Hearthttps://eheidi.dev/posts/freecad-heart-tutorialhttps://eheidi.dev/posts/freecad-heart-tutorialLearn an easy way to design a fully constrained 3D heart on FreeCAD using the Part Design and Sketcher workbenches, perfect for Valentine's Day!Fri, 13 Feb 2026 00:00:00 GMT<p>Valentine's Day is just around the corner, and what better way to celebrate than learning how to design a heart on FreeCAD? In this tutorial, you'll learn how to use arcs and constraints to create a fully constrained heart design that you can later pad into a 3D model and print with your 3D printer.</p>
<p>This tutorial focuses on the <strong>Sketcher</strong> and <strong>Part Design</strong> workbenches, and it's a great exercise to learn how to work with arcs, constraints, and degrees of freedom (DoF) on FreeCAD.</p>
<p>The full tutorial is available in video (below), but text instructions are included in the article for all steps, if you'd prefer to follow along by text.</p>
<p><iframe width="100%" height="540" src="https://www.youtube.com/embed/V-9S-ViKqs8?si=ml-LoR9Lnceu0nI1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Step 1: Create a New Project and Set Up the Part Design Workbench</h2>
<p>First, make sure you are in the <strong>Part Design</strong> workbench. You can select "Create a parametric part" on the starting page.</p>
<p>Create a new body by clicking on the "Create body" button, and then create a new sketch. You can also use the helper tools on the sidebar on the left. When prompted, select the <strong>XY plane</strong> as the base for your sketch.</p>
<h2>Step 2: Create the Top Arcs Using the Arc by Three Points Tool</h2>
<p>Now we'll create the top part of the heart using arcs. We'll use the X axis as a reference point to create symmetric arcs.</p>
<p>Select the <strong>arc tool</strong> from the toolbar. Instead of using "Create arc by center", choose <strong>"Create arc by three points"</strong>. This method is often easier to work with.</p>
<h3>Left Arc</h3>
<ol>
<li>Select the left point at the X axis (0,0 point)</li>
<li>Select a point to the right (this will be on the X axis as well)</li>
<li>Move your cursor up to define the arc's height</li>
<li>Make sure the arc connects to the X axis - you'll see a small indicator showing the point is constrained to the axis</li>
</ol>
<h3>Right Arc</h3>
<p>Repeat the same process for the right side:</p>
<ol>
<li>Start at the origin (0,0 point)</li>
<li>Select a point to the right on the X axis</li>
<li>Define the arc's height</li>
<li>Ensure it connects to the X axis</li>
</ol>
<p>Don't worry about the exact size at this point - we'll use constraints to set precise dimensions.</p>
<h2>Step 3: Set Radius Constraints for the Top Arcs</h2>
<p>Now let's set the radius for both arcs to make them equal in size.</p>
<ol>
<li>Select the first arc</li>
<li>Go to <strong>Constraint</strong> → <strong>Auto radius diameter</strong></li>
<li>Set the radius to <strong>16 mm</strong></li>
<li>Repeat for the second arc, also setting it to <strong>16 mm</strong></li>
</ol>
<p>You'll notice the "Solver Messages" showing that we still have degrees of freedom, meaning the sketch can still move.</p>
<h2>Step 4: Constrain Arc Centers to the X Axis</h2>
<p>To make sure the arcs stay in place, we need to constrain their centers to the X axis.</p>
<h3>Left Arc Center</h3>
<ol>
<li>Select the center point of the left arc</li>
<li>Hold and also select the X axis line</li>
<li>Apply the <strong>Coincident constraint</strong> (this makes the center "glued" to the X axis)</li>
</ol>
<h3>Right Arc Center</h3>
<p>Repeat the same process for the right arc's center point.</p>
<p>Now the sketch should be fully constrained, but it's not finished yet: the wires are open. We'll close it next with the bottom part of the heart.</p>
<h2>Step 5: Create the Bottom Arc</h2>
<p>The bottom of the heart will also be created using arcs. We'll use the same "Create arc by three points" tool.</p>
<h3>Left Bottom Arc</h3>
<ol>
<li>Select the left arc's bottom point as the starting point</li>
<li>Connect to a point on the Y axis (this will create the center point of the heart)</li>
<li>Define a slight curve for the bottom</li>
</ol>
<h3>Right Bottom Arc</h3>
<ol>
<li>Select the right arc's bottom point</li>
<li>Connect to the same center point on the Y axis</li>
<li>Create a matching curve</li>
</ol>
<h2>Step 6: Set Radius Constraints for the Bottom Arcs</h2>
<p>Apply the same radius to both bottom arcs to keep them symmetrical:</p>
<ol>
<li>Select the first bottom arc</li>
<li>Go to <strong>Constraint</strong> → <strong>Auto radius diameter</strong></li>
<li>Set the radius to <strong>54 mm</strong></li>
<li>Repeat for the second bottom arc, also setting it to <strong>54 mm</strong></li>
</ol>
<h2>Step 7: Set the Vertical Distance for the Bottom Point</h2>
<p>We still have one degree of freedom - the heart's bottom point can move up and down. Let's fix this by setting a vertical distance constraint.</p>
<ol>
<li>Select the bottom point of the heart (the point on the Y axis)</li>
<li>Also select the origin point (0,0)</li>
<li>Apply a <strong>Vertical distance</strong> constraint</li>
<li>Set the distance to <strong>40 mm</strong></li>
</ol>
<p>Your sketch should now be <strong>fully constrained</strong>! The Solver Messages should display "Fully constrained" and all lines should turn green.</p>
<h2>Step 8: Pad the Heart into a 3D Model</h2>
<p>Now that you have a fully constrained sketch, you can turn it into a 3D object:</p>
<ol>
<li>Close the sketch (this returns you to the Part Design workbench)</li>
<li>Select the <strong>Pad</strong> tool</li>
<li>Set the dimension to <strong>10 mm</strong> (1 cm)</li>
<li>Click OK</li>
</ol>
<p>And there you have it - a 3D heart model ready for Valentine's Day!</p>
<h2>Tips and Variations</h2>
<ul>
<li>You can adjust the radius values and vertical distance to create hearts with different proportions</li>
<li>Try using different pad heights to create hearts of varying thickness</li>
<li>Use the Fillet tool to round the edges for a smoother look</li>
<li>Export the model as an STL file (<strong>File</strong> → <strong>Export</strong> → <strong>STL Mesh</strong>) to 3D print your heart!</li>
</ul>
<h2>Conclusion</h2>
<p>Creating a fully constrained heart on FreeCAD is a great exercise to practice working with arcs, constraints, and the Sketcher workbench. The key concepts you learned here - using reference points, setting constraints, and managing degrees of freedom - are fundamental skills that you'll use in more complex FreeCAD projects.</p>
<p>I hope you enjoyed this tutorial, specially made for Valentine's Day! Check out more tutorials under the <a href="/tags/3d-printing">3d-printing</a> and <a href="/tags/freecad">freecad</a> tags to continue learning!</p>
Erika HeidiHow being a generalist is paying off in 2026https://eheidi.dev/posts/how-being-a-generalist-is-paying-off-in-2026https://eheidi.dev/posts/how-being-a-generalist-is-paying-off-in-2026Reflecting on how being a tech generalist has become increasingly valuable in the age of AI, from my early days as a solo developer to successfully executing modern projects with AI assistance.Wed, 11 Feb 2026 00:00:00 GMT<p>When I started working in tech some 20+ years ago, I lived in a small town and it was common to join companies where you'd be the sole developer, doing everything from back to front in order to get a website up and running. I wasn't very good with the front end, and eventually I joined a marketing agency with more developers, so I could focus on the back end. Nevertheless, I started learning from my colleagues, and eventually I built my first side project monetized by Google Adsense, which let me quit that job, pay for my college and basic expenses, and bootstrap my way out of Brazil with my partner.</p>
<p><img src="my-first-side-project.png" alt="Screenshot from Wayback Machine showing my first side project called "semfrescura.net"" />
<em>My first side project was a mix of community and online photo editing using PHP, GD and Imagemagick</em></p>
<p>At my first job in The Netherlands I was also a generalist. I was given the freedom to create a project from scratch and get it to production, working both on the front end as well as the back end. By this time we already had Twitter Bootstrap, so it was much easier to deal with CSS hell and get a base layout you could build out from.</p>
<p>Then, I attended my first international conference - it was the Dutch PHP Conference (DPC) in Amsterdam. I met several folks from the PHP community, and I was fascinated by all the talks I watched. Suddenly, I felt like being a generalist was a mistake; looking at all those talented speakers presenting on complicated topics as subject experts, I thought this was what I wanted for me. I wanted to be like them.</p>
<p>There was an issue though. I always had a hard time to focus on a single thing. I've always been that person with a million interests, several hobbies and unfinished projects. Studying was very hard if I didn't have a special interest I could apply. I could read ten books but I wouldn't really absorb anything if I couldn't try that in practice, and I wouldn't have enough motivation if I couldn't make it fun in some way. Maybe this was a "learning hack" I naturally developed since I was a kid. Truth is that this methodology was indeed helpful whenever I had to learn something, but most of the times I would learn things organically because I started a little side project in the first place.</p>
<p>While I was able to find a niche topic to focus and talk about (Vagrant, Ansible were my main topics during those years), I remained a generalist by heart. Life is too short to keep doing the same thing over and over! Doing different things and learning a bit about lots of stuff is what makes me happy. I sense I can always fill in the gaps if I really need to. My creativity takes me to lots of different places, and I like that.</p>
<p><img src="vagrant-cookbook.jpg" alt="Picture showing me in 2015 with a vibrant pink/red short hair holding a book in front of me, covering part of my face. The book has a bright yellow cover and has the title "Vagrant Cookbook" with black and blue thick letters, and a cupcake illustration." />
<em>Me in 2015 holding a printed copy of my self-published book, Vagrant Cookbook</em></p>
<p>I also sometimes thought about who would be in better position in a post apocalyptic scenario, or if stranded on an island, or if something really bad happened to the world or the tech industry 😅 for me, being a generalist was always the safest bet.</p>
<p>Fast-forward to 2026. All we hear and read about is AI - it will take our jobs, it will change the Industry forever, it will turn anyone into a developer. As much as I don't believe that it will take our jobs or that it will turn anyone into a developer, today I <em>do</em> believe it will change our Industry forever. It's hard to predict how this change will materialize in one or two years, but the shift is clear and already happening.</p>
<p>Being a tech generalist in 2026 is already paying off for me. I was able to execute a work project from start to finish all by myself in a couple weeks, from zero to deployed to GCP (something I haven't done before) with advanced features that would take me months to accomplish without the help of a coding agent. I trust the output because I know the stack well enough, and thanks to my generalist background I was able to understand everything going under the hook and even learned a bunch of new tricks along the way. Not to say that it was trivial or that I didn't get stressed out by Claude sometimes, but the coding agent has unlimited stamina and motivation. It just keeps going until it works, something I personally have trouble with.</p>
<p>I know I might disappoint a few friends by telling all this, but the change is already here, and we must find a way to adapt. AI won't take our jobs, but it is not going anywhere. It is important to find a way to navigate this new world, and if you are a creative generalist like me, you may even enjoy it. The question I often ask myself now is what really makes me happy about code. Is doing things the hard way what makes us proud? I am still figuring that out, and a bunch of other things, but what I really wanted to say is: yes, being a generalist is (finally?) paying off.</p>
Erika HeidiUsing Spreadsheets and Formulas on FreeCADhttps://eheidi.dev/posts/freecad-spreadsheets-formulashttps://eheidi.dev/posts/freecad-spreadsheets-formulasLearn how to use the Spreadsheet workbench and formulas in FreeCAD to create completely dynamic parametric objects that update automatically when you change values.Fri, 06 Feb 2026 00:00:00 GMT<p>One of the most powerful features of FreeCAD is its ability to create parametric designs - objects that can be dynamically updated by changing values in a spreadsheet. This technique allows you to design once and adapt your creation to different sizes and purposes without starting from scratch.</p>
<p>In this tutorial video, you'll learn how to use the <strong>Spreadsheet workbench</strong> and <strong>formulas</strong> in FreeCAD to create a parametric pen holder that automatically updates when you change spreadsheet values. This same technique can be applied to create any kind of container - from jewelry boxes to candy holders and desktop organizers.</p>
<h2>What You'll Learn</h2>
<p>In this tutorial, we'll cover:</p>
<ul>
<li>How to create and use a spreadsheet to store design parameters</li>
<li>How to reference spreadsheet values in your sketches using formulas</li>
<li>How to create dynamic constraints that update automatically</li>
<li>Best practices for creating parametric designs with proper thickness calculations</li>
</ul>
<p><iframe width="100%" height="540" src="https://www.youtube.com/embed/pwbyAbR-mwE?si=Cf-jQJ0g3tb6uqCP" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Tutorial Steps</h2>
<h3>Step 1: Create a Spreadsheet</h3>
<p>Start by creating a spreadsheet in FreeCAD to store all the parameters for your design. We'll use:</p>
<ul>
<li><strong>Column A</strong>: Reference labels for each parameter</li>
<li><strong>Column B</strong>: Values that will be used in formulas</li>
</ul>
<p>The parameters we'll define include:</p>
<ul>
<li><strong>Width (B1)</strong>: 60 mm - the outer width of the container</li>
<li><strong>Height (B2)</strong>: 40 mm - the outer height of the container</li>
<li><strong>Pad/Depth (B3)</strong>: 100 mm - the depth of the container (10 cm)</li>
<li><strong>Thickness (B4)</strong>: 2 mm - the wall thickness</li>
</ul>
<h3>Step 2: Create the Base Object with the Part Design Workbench</h3>
<p>Switch to the <strong>Part Design</strong> workbench and create a sketch on the XY plane. This will be the outer dimensions of your container.</p>
<ul>
<li>Set the <strong>width</strong> using the formula: <code>spreadsheet.B1</code> (60 mm)</li>
<li>Set the <strong>height</strong> using the formula: <code>spreadsheet.B2</code> (40 mm)</li>
</ul>
<p>Once your sketch is complete, use the <strong>Pad</strong> tool to extrude it. For the pad dimension, use the formula: <code>spreadsheet.B3</code> (100 mm).</p>
<h3>Step 3: Create the Inner Pocket</h3>
<p>Create a new sketch on the top face of your padded object. This sketch will define the inner cavity of the container.</p>
<p>The inner dimensions need to account for the wall thickness on both sides:</p>
<ul>
<li>
<p><strong>Inner width</strong>: Use the formula <code>spreadsheet.B1 - 2 * spreadsheet.B4</code><br />
This subtracts the thickness from both sides (60 - 2×2 = 56 mm)</p>
</li>
<li>
<p><strong>Inner height</strong>: Use the formula <code>spreadsheet.B2 - 2 * spreadsheet.B4</code><br />
This subtracts the thickness from both sides (40 - 2×2 = 36 mm)</p>
</li>
</ul>
<p>Next, use the <strong>Pocket</strong> tool to create the hollow interior. For the pocket depth, use the formula:</p>
<p><code>spreadsheet.B3 - 2 * spreadsheet.B4</code></p>
<p>This creates a pocket that leaves material at the bottom, ensuring consistent thickness throughout the container.</p>
<h3>Step 4: Add Fillets</h3>
<p>Add <strong>fillets</strong> to round the corners of your container. When choosing the fillet radius, keep the wall thickness in mind - if the fillet is too large relative to the wall thickness, the object might break when you change parameters later.</p>
<h3>Step 5: Test the Parametric Design</h3>
<p>Here's where the magic happens! Go back to your spreadsheet and change any of the values:</p>
<ul>
<li>Try changing the width to 80 mm</li>
<li>Adjust the height to 50 mm</li>
<li>Modify the thickness to 3 mm</li>
</ul>
<p>Watch as your entire container updates automatically, maintaining all the proper relationships between dimensions!</p>
<h2>Key Takeaways</h2>
<p>The Spreadsheet workbench in FreeCAD is an incredibly powerful tool for creating dynamic, parametric designs. By defining your dimensions in a spreadsheet and referencing them with formulas, you can:</p>
<ul>
<li><strong>Save time</strong>: Design once, generate multiple sizes instantly</li>
<li><strong>Maintain consistency</strong>: All related dimensions update together</li>
<li><strong>Reduce errors</strong>: Formulas ensure proper relationships between dimensions</li>
<li><strong>Increase flexibility</strong>: Easily adapt your design for different purposes</li>
</ul>
<p>This technique is perfect for creating containers, organizers, holders, and any other object where you might need different sizes. Whether you're designing a pen holder, a jewelry box, or a storage container for small desktop items, the spreadsheet approach gives you maximum flexibility with minimal effort.</p>
<h2>Next Steps</h2>
<p>Now that you understand how to use spreadsheets and formulas in FreeCAD, try applying this technique to your own projects. Start with simple objects and gradually incorporate more complex formulas and relationships.</p>
<p>For more FreeCAD tutorials, check out the other posts under the <a href="/tags/freecad">freecad</a> tag!</p>
Erika HeidiFreeCAD Tutorial: Pen Holderhttps://eheidi.dev/posts/freecad-tutorial-penholderhttps://eheidi.dev/posts/freecad-tutorial-penholderLearn how to create a 3D printable pen holder on FreeCAD, using the Part Design and Sketcher workbenches.Thu, 05 Feb 2026 00:00:00 GMT<p>Sketcher and Part Design are two <a href="https://wiki.freecadweb.org/Workbenches">FreeCAD workbenches</a> that work closely together, typically used to turn 2D geometries into 3D models. In a nutshell, through the Sketcher workbench you create the blueprints of parts that are manipulated through the Part Design workbench.</p>
<p>We'll now see how to use the Sketcher and Part Design workbenches to create a minimalist pen holder model that you can print with a 3D printer.</p>
<p>Before continuing, it is important that you have FreeCAD installed on your machine, and that you are familiar with how to navigate the interface. If you haven't checked my previous post on <a href="/posts/freecad-for-beginners">FreeCAD for Beginners</a>, now is a good time do to so!</p>
<p>The full tutorial is available in video (below), but text instructions are included in the article for all steps, if you'd prefer to follow along by text.</p>
<p><iframe width="100%" height="540" src="https://www.youtube.com/embed/t_e96M4iLN4?si=q-ax6Ob6K7a4fLzc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Step 1: Create a new project, then move to the Part Design workbench</h2>
<p>Create a new project, then select the "Part Design" workbench on the workbench selection box.</p>
<h2>Step 2: Create a new body, and then create a new Sketch. Choose XY as base plane.</h2>
<p>You can use the shortcuts on the left sidebar to create a new body, and then create a new sketch on that body. When creating the sketch, select the XY_Plane.</p>
<h2>Step 3: Select the square/rectangle tool, then create a rectangle at the center of the canvas.</h2>
<p>Don't worry about the size now, we'll set up constraints in the next step.</p>
<h2>Step 4: Centralize the object with the symmetry constrain</h2>
<p>Constraints allow you to specify a set of rules that can be applied to points, lines, and angles. This constrains creates a symmetry rule between two points and a reference line or point.</p>
<p>Select the the top left point of the sketch, the bottom right point of the sketch, and then the 0,0 point of the plane. Then, select the symmetry constrain to centralize the object.</p>
<h2>Step 5: Select the horizontal width constraint, then set the size of 60mm.</h2>
<p>If you look at the "Solver Messages" dialog on the top left, you'll notice it says "Under-constrained: 2 DoF(s)". This means your design is not "locked in place", and there are 2 dimensions in which it can move. That might not seem like a big deal (and in many cases it isn't), but it's preferable to have your sketch fully constrained to serve as solid base for other parts of your design.</p>
<p>We'll now set the horizontal width constrain to limit the horizontal size of the object.</p>
<h2>Step 6: Select the vertical width constraint, then set the size of 40mm.</h2>
<p>Repeat the process to set up the vertical width of the pen holder.</p>
<p>You'll notice that as soon as you finish setting up the width and height constrains, your sketch will be green and the Solver messages dialog will display <strong>Fully constrained</strong>.</p>
<h2>Step 7: Select the pad tool and pad to the height of 100mm.</h2>
<p>Close the sketch. This will bring you back to the Part Design workbench, automatically. You can then select the pad tool, setting the type to Dimension and the height to 100mm. Click "ok" to confirm.</p>
<h2>Step 8: Create a new sketch based on the top face.</h2>
<p>Select the top face of the object, then click on the sketch button to create a new sketch using that face as attachment.</p>
<p>:::tip
All sketches must be attached to a plane or face. When we first created a sketch in Step 2, we attached it directly to the XY plane. This time we're attaching the sketch to an existing face.
:::</p>
<h2>Step 9: Create a rectangle form slightly smaller than the first one, using the constraints of 56mm and 36mm for width and height, respectively.</h2>
<p>Repeat the process from steps <strong>3</strong> to <strong>6</strong> to create a smaller rectangle of 56x36mm inside the previous one. We'll use this sketch to create a "pocket", turning the initial rectangle in a box, leaving 2mm at each side as border. Make sure it's centralized so all borders have the same thickness.</p>
<p>This is how the sketch should look like when you're finished:</p>
<p><img src="part9.png" alt="Creating a new rectangle to use with the pocket tool" /></p>
<h2>Step 10: Use the pocket tool to hollow the model.</h2>
<p>Close the sketch, and you will be brought back to the Part Design workbench. Then, use the pocket tool instead of pad - this time we want to create a pocket to make the model hollow. Select the "Dimension" type and the length of 90mm, which will leave 1cm for the bottom.</p>
<h2>Step 11: Use the fillet tool to round the edges slightly.</h2>
<p>For a final detail, you can use the fillet tool to round some edges. Select one of the faces of the model, then select the "Fillet" tool. Click on the "add ref" button to add all external faces, one by one. Rotate the model and add the other faces. You can use the radius of 1mm for a discrete effect. When you're done, click the "OK" button.</p>
<p>And it is done! If you want to print this model, you can export it through the menu <code>File -> Export</code>, then choose the <strong>STL</strong> format. You can then import the STL to a slicer software to get it ready for printing.</p>
<p>I hope you have enjoyed this tutorial. Check also other posts under the <a href="/tags/3d-printing">3d printing</a> tag!</p>
Erika HeidiIs it Really an Ego Issue? The Problem with AI-generated Codehttps://eheidi.dev/posts/is-it-really-an-ego-issuehttps://eheidi.dev/posts/is-it-really-an-ego-issueCalling it an ego issue is an over simplification. There is a lot more to it...Mon, 02 Feb 2026 00:00:00 GMT<p>I have been asking this question a lot lately: is it really an ego issue? Why using AI tools give me this uncomfortable feeling, even when I like the result?</p>
<p>First of all, I am not anti-AI, and I am actively using it today for my work and even for <a href="https://eheidi.dev/posts/laravel-boost-copilot">side projects</a>. I am not saying it is not useful, and I am not going into the ethical or environmental issues of AI usage. It is not in the scope of this rant.</p>
<p>I am talking about personal feelings and career goals.</p>
<p>A <a href="https://x.com/karpathy/status/2015883857489522876">viral post from Andrej Karpathy</a>, one of the founding members of OpenAI, highlights how using AI coding agents has transformed his work while admiting that it does "hurt the ego a bit":</p>
<blockquote>
<p>It hurts the ego a bit but the power to operate over software in large "code actions" is just too net useful, especially once you adapt to it, configure it, learn to use it, and wrap your head around what it can and cannot do.</p>
</blockquote>
<p>I favorited his original post on X because I found it insightful, and since then I cannot stop thinking about it - is it really an ego issue what I'm feeling?</p>
<p>I never took issue in receiving contributions or feedback on my code, and I always thought that collaboration is key for software projects, especially open source ones. I never felt it hurted my ego, so why would a non-human contribution hurt my ego?</p>
<p>I think the issue goes a bit deeper than that. I used to feel proud of my code and my engineering work. I would look at a semi-finished project (well, all coding projects are semi-finished, as software is never complete) and think "wow. I built all this!" And that was enough to make me happy, even if the project was not perfect (it never was) and the TODO list was big. Even if it took me several weeks to get there. I could see the repercussions. People would be genuinely interested when the project was useful to them.</p>
<p>Now, code is cheap. It doesn't matter how the code looks, and people just don't care anymore, because they can "build a replica with Claude Code in less than one day", getting whatever engagement might come from yet another copy of something that could have been good if people would just collaborate more. At the same time, open source maintainers are already overwhelmed by low-quality, poorly designed pull requests made entirely with AI tools where folks don't even understand what the changes do to the project, ignoring future repercussions and based on naive assumptions.</p>
<p>Yeah, I built a cool app with Copilot in under a month, but I just don't feel like open sourcing it. I understand <em>most</em> of the code, but I don't feel proud of it; is this what we'll be doing in the next 5 years? Do we really need all this velocity, instead of the slower but steady pace of well-crafted, thoroughly designed software?</p>
<p>And most importantly: who is gonna review all this shit?</p>
<p>Review fatigue is real, and it sucks. As much as you want to oversee all steps along the way, there is no way you can ship at that speed if you thoroughly review everything the LLM does in your codebase. Been there, done that. It's just not possible. You start with good intentions and sharp eyes, but at some point you'll just let go.</p>
<p>Is this the future we want after years, decades of study and practice improving our coding skills? I understand that "the genie is out of the bottle" and there's no way it's coming back, but the environment that is being shaped up is just not sustainable in the long term! With less people willing to share open source and less people learning in public (see the decline in Stack Overflow), soon there will be no more "free lunch" for LLMs to get trained, and the overall quality and security of AI-generated code tends to get much worse.</p>
<p>But yeah, let's call it an ego issue 🤙🏻</p>
Erika HeidiUse the Right Tool for the Job and your Skillsethttps://eheidi.dev/posts/use-the-right-tool-for-the-job-and-your-skillsethttps://eheidi.dev/posts/use-the-right-tool-for-the-job-and-your-skillsetLet me tell yall the story of how I sabotaged myself (and my own progress) by insisting on using a tool that was not the right choice for me. Wed, 28 Jan 2026 00:00:00 GMT<p>Choosing the right tool for the job can be challenging because it's not just about what's best for that specific use case, but also what works best for you, given your skill level, your personal goals, and how comfortable you feel with the tool so that you can advance at a reasonable speed.</p>
<p>Let me tell y'all the story of how I sabotaged myself (and my own progress) by insisting on using a tool that was not the right choice for me.</p>
<p>Last year, after being convinced by my daughter (9) who started having climbing lessons in her after-school program, I started climbing too. Indoor bouldering is a fairly popular sport here in The Netherlands, with several climbing gyms throughout the country. And so it happened that a climbing gym opened very close to our home, so it was a) convenient (both because it was close but also because it's an indoor sport so you don't depend on the weather); b) fun; and 3) very challenging.</p>
<p>Bouldering in general requires the use of special shoes. Climbing shoes are known for being uncomfortable, so it takes some time to get used to them. It took me quite a few attempts to find a pair of climbing shoes that I was able to use without too much pain. Usually, as a beginner you start with a shoe two (sometimes three) sizes bigger than your regular shoe size.</p>
<p>And that was fine. My first pair was two sizes bigger and it was good for a long time! I was progressing.</p>
<p><img src="climbing.jpg" alt="The image shows an indoor climbing wall with colored boulders. I stand on top of two big blue holds while holding with both hands a big blue holder that is the end of that route. The routes have different numbers, and the one I am finishing is a 5." /></p>
<p>Fast-forward to some 6 months later, my right shoe now had a hole in the tip, and it was very slippery. It was time to go for my <em>second</em> pair of climbing shoes.</p>
<p>And that's when the problems started. Because I had progressed a lot in that period, I thought I was ready for "the next step", getting a shoe slightly smaller for better performance. I believed that was the next logical step in my climbing progress. I did my research, and I bought a new pair that was size 40 (my regular size is 39, EUR size). My first pair was 41.</p>
<p>At first I was impressed because the new shoes were really good! Perfect grip, great tip. Or course, they were not comfortable. It was painful but I thought I just needed to get out of my comfort zone for a while, until the shoes felt good. They did get better, but it was still painful. I started having some pain in my big right toe outside of the climbing session, and during the climbing sessions it started to become clearly unbearable: I was afraid of jumping because it hurted my feet, I lost my confidence, and I just stopped progressing at all, always thinking that with just a few more sessions I would finally get used to these damn good shoes. Which I didn't.</p>
<p>Eventually I realized I wasn't ready for the damn good climbing shoes and I should just go a step back to my beginner shoes. Even with a hole in one of them, I was able to climb so much better! So I got yet another pair of climbing shoes, this time a bigger size (back to 41) and with laces, so that I could tie them well and make them adapt to my weird, wide feet.</p>
<p>And just as expected, I started progressing again.</p>
<p><img src="shoes-compared.jpg" alt="Both shoes compared - the blue and black shoe is the extra tight MF and the white and black one is my new pair that I love." />
<em>I think it is clear who is who in this picture, right? The white and black one is my new favorite!</em></p>
<p>Don't let yourself be influenced by all the hype out there; give yourself the space to grow and learn at a pace that is not too comfortable but also not too aggressive that will burn you out. As a beginner you may feel tempted to skip steps in order to progress faster, but that will cause other foundational issues that you can't predict. Keep the pace, ignore the FOMO, choose the right tools for you and don't get fooled by a damn good pair of unbearably tight shoes 😄</p>
Erika HeidiBuilding a Karaoke App with Laravel Boost and Copilothttps://eheidi.dev/posts/laravel-boost-copilothttps://eheidi.dev/posts/laravel-boost-copilotIn this post I share my experience building an app with an impossible deadline, using Laravel Boost and Copilot. I will keep upating this post as I make progress in the project.Sat, 13 Dec 2025 00:00:00 GMT<p>As some of you may know, I am from Brazil. Brazilians love music, and it's not different within my family! Every time I go to Brazil, we have karaoke parties. Our setup for karaoke is quite simple, with a speaker and two microphones connected directly to it, and a phone connected via bluetooth, playing YouTube karaoke songs.</p>
<p>This year I thought: "what if I build a little app to improve our setup?". The app could still use YouTube (with embeds) as a source of karaoke songs, since making the songs was out of the table. Keeping it simple, I could build an app to make the experience more integrated and social.</p>
<p>There was just one small problem: I only had two weeks :D I am going to Brazil for the Holidays, and there's just no time left to develop such a thing. But wait... What if I use Copilot? With AI assistance, <em>maybe</em> I could pull this up. Mind you that I still have to work and handle life in general in this time frame, so I will be coding mostly after working hours and in the two weekends I have before traveling.</p>
<p>Mind you that I have been very skeptical about <em>vibecoding</em> in general so far, being a firm believer that vibecoding is just a quick way to introduce tech debt to your app. But this idea created the perfect opportunity to put this to test, and evaluate what's currently possible with Copilot. I decided to use a stack I am very familiar with: Laravel + Livewire, with TailwindCSS. Mind you that I haven't touched Laravel code in about 2 years, so I knew a lot of things have probably changed, but the core was the same and it would be easier for me to debug and understand what was going on.</p>
<p>I also defined the most important features I wanted in my karaoke app:</p>
<ul>
<li>Catalog with curated karaoke videos from YouTube (will need a CRUD for that)</li>
<li>A Player endpoint that would play the songs in the queue (probably Javascript-heavy, since it needs to skip songs, auto update, etc)</li>
<li>A way for players to join a single session together and interact</li>
<li>A way for players to add songs to the queue</li>
</ul>
<p>In this post, I will share my experience in the past week building this app. Is it really possible to develop an app like this in such a short timeline? The TL;DR is: yes, if you kinda know what you're doing.</p>
<p>I made this silly video to show off:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/9hURUE1K9Fk?si=zZrFgAAMILc-l_0K" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Phase 1: Off to a Bumpy Start</h2>
<p>In my first experiment, I bootstrapped a new Laravel app following official docs, but I did <strong>not</strong> know what <a href="https://laravel.com/ai/boost">Laravel Boost</a> was, so I chose not to install it. That was my first mistake.</p>
<p>After I had a basic Laravel app with Livewire up and running, I asked Copilot (in Agent mode) to implement the Song model and CRUD, with dashboard pages to manage all (this in a single prompt - my second mistake). I was using the default model that comes pre-selected (gpt5-mini). Copilot proceeded with the implementation and soon I had some dashboard pages where I could manage Songs. Impressive! This was working, but did not use Livewire at all. I forgot to mention that in my prompt, so it just created regular controllers under authentication. I asked it to update to use Livewire, and it did re-implement the CRUD features using a Livewire component, but left the controllers there "just in case".</p>
<p>It did not work at first, thou. Then I realized it was saving Livewire components to the wrong folder. I also got Javascript errors about a call to an undefined "emit" method. I then realized it was using Livewire 2 syntax, but we had Livewire 3 in our project. I fixed it, but every time I asked for a Livewire thing, it would do this, I would have to fix, and things started to look chaotic fast. It also didn't leverage <a href="https://livewire.laravel.com/docs/3.x/volt">Volt</a>, and I personally did not know what that was either. Later on I read the documentation and realized Volt would facilitate SO MUCH writing Livewire components because you could have everything in a single file.</p>
<p>That's when I got an email from the <a href="https://stars.github.com/">GitHub Stars</a> program asking us Stars to try a new model that was being made available to us for feedback. Since I was already in this quest, I decided to give it a try.</p>
<h2>Phase 2: A New Hope</h2>
<p>To use the new model, I had to install VS Code Insiders, which is a version of VS Code for early adopters. It lets you try the most recent features of VS Code without changing your default installation. As soon as I opened the project in VS Code Insiders, Copilot asked if I wanted to generate a helper file (copilot-instructions) to facilitate AI assistance in this code base. I said YES.</p>
<p>I then asked it to create new Livewire components and it got it right in the first try. No more outdated syntax. The code looked very good and organized, in line with the official docs. Still not using Volt, but overall much better.</p>
<p>Things started to get more complex as I moved to more complicated features that used a lot of Javascript. While implementing the Player, Copilot suggested using Broadcasting with Reverb - another shiny thing I knew nothing about. I accepted the suggestion and <em>some</em> things worked, but I couldn't figure out why all the other things were not working. The player template looked very complex with tons of JS. I would prefer things a bit simpler, and I couldn't really understand the interactions happening between Livewire and Reverb / Echo.</p>
<p>Honestly, it just felt like I did not know what I was doing, and I was not in control.</p>
<p>That's when I decided to start fresh. With several lessons learned on how to deal with the process and how to ask for what I wanted, I bootstrapped a <strong>new</strong> Laravel project, and this time I did install Laravel Boost.</p>
<h2>Phase 3: I'm Again in Control</h2>
<p>Laravel Boost created a copilot instructions file right away during installation, and the whole experience was <strong>completely</strong> different. Instead of creating all files manually, Copilot now was using the proper Artisan commands to do everything, which improved the code standards and organization by a ton. This really made a huge difference. I even reproduced the issue to prove my assumptions, here is the comparison before and after installing Laravel Boost on a fresh Laravel application:</p>
<p><img src="laravel-boost-before-after.png" alt="The image shows two panels, both showing a Copilot chatbot window, asking the question: "what is the correct location for Livewire component logic". The left one has a red title "Without Laravel Boost", and a red circle highlights that the AI chat replies with the wrong location (app/Http/Livewire). The right panel shows the correct answer (app/Livewire), there's a green text saying "With Laravel Boost" and a circle highlighting the correct location for Livewire components as answered by the chat bot. Both use the same model (gpt5-mini), so it's clear the difference was caused by having Boost installed." /></p>
<p>This time around, I did plan <strong>everything</strong> beforehand, and I asked Copilot to implement small steps each time. For example, I asked first for a Song Eloquent model, with migration and tests; after that was done and working, I asked for the CRUD implementation in the dashboard, using standards already present in the project. It worked flawlessly, using Livewire with Volt.</p>
<p>Another important measure that I took was creating a Git branch every time I was going to implement a new feature. Commit everything and have separate branches so you can revert easily when things don't work right away.</p>
<p>One thing I realized is that when things don't work, you have to be careful because the AI agent will try <em>hard</em> to fix it in any way possible, which can introduce a lot of code you don't fully understand. Things start to get complex (while still not working), and if they do work eventually, you already lost track of what was the real issue. My advise is to don't dig too much, be ready to revert early if some fix didn't work, before changes get out of your control.</p>
<h2>Biggest Challenges</h2>
<p>So far, the biggest challenge has been implementing <a href="https://laravel.com/docs/12.x/broadcasting">Broadcasting</a> with Laravel <a href="https://laravel.com/docs/12.x/reverb">Reverb</a>. I first tried with Copilot implementing everything for me, but it did not work. Events were not being triggered at all, no errors and nothing on the logs to indicate the problem. Since this touches many different parts of the application (including front-end), it was a critical implementation and I felt that I should dedicate time to go through a manual implementation this time.</p>
<p>So I reverted the changes and followed the docs thoroughly in order to integrate Reverb and Echo in my application. This time, I finally understood how things get wired, how the subscription with Echo works in the front end, and how to interpret the logs at each side (Laravel logs and Reverb logs). I got as far as dispatching jobs (I could see them being worked in the queue logs), but the events would still not reach Echo.</p>
<p>After spending quite some time trying to fix this (and knowing I was <strong>so</strong> close), I asked Copilot to help investigate and debug the problem. Took Copilot 10 minutes but it did find the problem and fixed it. There was a missing ServiceProvider in my app, so the events where triggered but not broadcasted (and also no errors thrown). There was nothing about a ServiceProvider in the official documentation, so I was impressed it could find and fix the issue.</p>
<p>While Laravel Reverb has made a big difference in the overall development process, I believe the model I'm testing is far superior then gpt-mini, so there's that too.</p>
<h2>Wrapping Up</h2>
<p>Today, at the one week mark, I have about 80% of the application ready. Broadcasting is working, I can manage Songs and Tags from the dashboard, the player is working with auto-forward and all, the queue is working with songs added by different users, and there is a companion mode to join the session from a mobile phone. Of course, there are some rough edges to smooth out, front-end adjustments, and a few other details. But the bulk of it is already working, which is great! I am very surprised by this experience, I did not think it would go the way it went.</p>
<p><img src="singwithme.png" alt="Sing With Me preview" /></p>
<p>With regards to AI assisted coding, my key takeaways are:</p>
<ul>
<li>Always be in control</li>
<li>YOU should be the architect; don't let AI make important decisions on your behalf</li>
<li>Commit often, revert when things start to get weird (and you feel you're losing control)</li>
<li>Know your stack, have the docs open at all times</li>
<li>Don't be lazy - read the docs, understand what is being implemented, touch the code whenever necessary</li>
<li>Always be in control</li>
</ul>
<p>I'll be sharing another update after we test-drive the app! :)</p>
<h2>2-Week Update (Dec 23)</h2>
<p>It's almost Christmas and I had some progress I wanted to share, as well as my honest opinion about the models I have tried (Claude Opus and GPT Codex Max) so I recorded this video update. TL;DR: there are still some things to fix, and I had some issues with the Reverb server on Laravel Cloud, but things are progressing as I just finished setting up a better development environment using Docker Compose. I also need to improve the process for adding new songs, making song curation easier.</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/e-G3_OD8SKU?si=w0WlTCZwYppDleLz" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
Erika HeidiRunning Open Source LLMs on a Raspberry Pi 5 with Llama.cpphttps://eheidi.dev/posts/raspberry-llamahttps://eheidi.dev/posts/raspberry-llamaLearn how to set up a Raspberry Pi 5 to run open source LLMs in your local network using Llama.cppFri, 14 Nov 2025 00:00:00 GMT<p>For a long time, I also felt skeptical about LLMs and what they are capable of. The biggest issue for me is the push we're currently seeing from corporations, claiming productivity gains and even the complete replacement of human roles. As an expectator and occasional consumer of chatbots, I started resenting anything that has AI in its name and rolled my eyes at every AI LinkedIn post I saw. I did not want to take part in it.</p>
<p>But that's where things get complicated. If not us, who? Should we let corporate greed drive this future? Or should we, as open source ambassators, get organized and start digginng further to use this technology for public goods? I believe that's the whole idea behind <a href="https://huggingface.co">HuggingFace</a>, an open source AI platform and community with almost 4 million open source LLMs that can be downloaded and used for free in your own infrastructure. Combined with <a href="https://github.com/ggml-org/llama.cpp">LLama.cpp</a>, an open source LLM inference tool written in C++ (very efficient while broadly compatible)</p>
<p>I am not talking about prompt engineering and vibe coding, but actually finding real use cases for LLMs where traditional approaches did not work well. Accessibility is a great example of that; nobody likes (or actually knows how to) to write good ALT descriptions for images, something that is achievable with LLMs trained on computer vision.</p>
<p>In this tutorial, you'll learn how to set up a Raspberry Pi 5 on your local network to run open source LLMs from HuggingFace, using a containerized environment running Llama.cpp. For this example we'll use the <a href="https://qwen.ai/blog?id=99f0335c4ad9ff6153e517418d48535ab6d8afef">Qwen3-VL</a> LLM from Alibaba Cloud, an open source LLM with advanced text and visual capabilities. According to the <a href="https://www.alibabacloud.com/blog/602584">release blog post</a>:</p>
<blockquote>
<p>The goal of Qwen3-VL is not just to "see" images or videos — but to truly understand the world, interpret events, and take action. To achieve this, we’ve systematically upgraded key capabilities, pushing visual models from simple “perception” toward deeper "cognition", and from basic "recognition" to advanced “reasoning and execution.”</p>
</blockquote>
<p>To make our system extra secure, we'll use the <a href="https://www.chainguard.dev/unchained/a-gift-for-the-open-source-community-chainguards-cve-free-raspberry-pi-images-beta">Chainguard OS Container Host for Raspberry Pi</a>, because it contains zero vulnerabilities and already comes with a built-in Docker daemon, so we can get up and running very quickly with a somehow reproducible setup (you still need to manually create the Raspberry Pi boot disk). We'll also use a Wolfi-based container image (<strong>gcc-glibc</strong>) as base for our Dockerfile, since we'll need to build Llama.cpp from source.</p>
<h2>Prerequisites</h2>
<p>Here are the things you'll need in order to follow this tutorial:</p>
<ul>
<li>A Raspberry Pi 5
<ul>
<li>A mini hdmi to hdmi cable to connect your Raspberry Pi to a display</li>
<li>A keyboard</li>
<li>An ethernet connection</li>
</ul>
</li>
<li>A microSD card (and a microSD reader for your computer so you can build a bootable disk)</li>
<li>Power source for the Raspberry</li>
</ul>
<p>To keep things simple and fast, I'm using an ethernet cable plugged directly to my wi-fi modem. The Raspberry Pi gets an IP address from DHCP, and the easiest way to find the IP is to just log into the Raspberry and run <code>ip addr</code> to find your local network IP.</p>
<p>The containerized setup also works on a regular computer - in this case, you only need Docker.</p>
<h2>Building the Bootable Disk with Chainguard OS</h2>
<p>The first thing you'll need to do is to obtain the image for your Raspberry Pi and use it to create a bootable disk in a microSD card. Go to <a href="http://images.chainguard.dev/rpi">this link</a> and use the form to download the <strong>Chainguard Raspberry Pi Docker Image</strong>.</p>
<p>You'll get a <code>.raw.gz</code> file. Unpack the file with:</p>
<pre><code>gunzip rpi-generic-docker-arm64-*.raw.gz
</code></pre>
<p>Plug your microSD card to your computer and locate the disk name (for instance, /dev/sda). Then, run:</p>
<pre><code>sudo dd if=rpi-generic-docker-arm64-*.raw of=/dev/sda bs=1M
</code></pre>
<p>After this proccess is finished, unmount and remove the microSD from your computer and place it on the Raspberry Pi.</p>
<h2>Booting your Pi and Finding your IP Address</h2>
<p>Connect a display and keyboard to your Pi, and the ethernet cable, then, boot it up. You can login with user <strong>linky</strong> and password <strong>linky</strong>.</p>
<p>Then, run <code>ip addr</code> to find out what IP address was given by DHCP to your Pi. You should look for something like this, an <code>end0</code> interface:</p>
<pre><code>2: end0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 2c:cf:67:b9:30:93 brd ff:ff:ff:ff:ff:ff
altname enx2ccf67b93093
inet 192.168.178.36/24 metric 1024 brd 192.168.178.255 scope global dynamic end0
valid_lft 52735sec preferred_lft 52735sec
inet6 2001:1c00:1519:a500:2ecf:67ff:feb9:3093/64 scope global dynamic mngtmpaddr noprefixroute
valid_lft 604785sec preferred_lft 604785sec
inet6 fe80::2ecf:67ff:feb9:3093/64 scope link proto kernel_ll
valid_lft forever preferred_lft forever
</code></pre>
<p>In this case, the Pi address is <strong>192.168.178.36</strong>. You can already go back to your computer (on the same local network) and access the Pi from SSH:</p>
<pre><code>ssh linky@RASPBERRY_IP_ADDRESS
</code></pre>
<p>Use <strong>linky</strong> as the password. Now you can control everything from the terminal on your computer.</p>
<h2>Chainguard OS Setup</h2>
<p>Unlike Debian-based distros such as Ubuntu, Chainguard OS is based on apk, which makes it similar to Alpine. To update the package manager cache, run:</p>
<pre><code>apk update
</code></pre>
<p>We'll need some additional packages to facilitate setup. Run:</p>
<pre><code>apk add curl git vim
</code></pre>
<p>You don't need to install Docker, as it's already up and running in this Pi image:</p>
<pre><code>sudo systemctl status docker
</code></pre>
<pre><code>● docker.service - Docker Application Container Engine
Loaded: loaded (]8;;file://localhost/usr/lib/systemd/system/docker.service\/usr/lib/systemd/system/docker.service]8;;\; enabled; preset: enabled)
Active: active (running) since Wed 2025-11-12 13:47:08 UTC; 2 days ago
Invocation: 3771db7beb624e819b2eec8b7c5e446f
TriggeredBy: ● docker.socket
Docs: ]8;;https://docs.docker.com\https://docs.docker.com]8;;\
Main PID: 14287 (dockerd)
Tasks: 30
CPU: 40.696s
CGroup: /system.slice/docker.service
├─14287 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
├─21227 /usr/sbin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 25565 -container-ip 172.19.0.2 -container-port 25565 -use-listen-fd
└─21233 /usr/sbin/docker-proxy -proto tcp -host-ip :: -host-port 25565 -container-ip 172.19.0.2 -container-port 25565 -use-listen-fd
</code></pre>
<h2>Building the Container Image</h2>
<p>To run our LLMs, we'll be using a containerized environment where we'll build Llama.cpp from source, following the <a href="https://github.com/ggml-org/llama.cpp/blob/master/docs/build.md">official build instructions</a> from the project's repository.</p>
<p><a href="https://github.com/erikaheidi/wolfi-llama/blob/main/Dockerfile">This Dockerfile</a> uses a zero-CVE container image from Chainguard to build Llama.cpp and get its built-in web interface up and running. The web interface is very similar to ChatGPT, but uses your own infrastructure and open source LLMs.</p>
<p>From inside your Pi (either via SSH or with direct access), clone the demo repository:</p>
<pre><code>git clone https://github.com/erikaheidi/wolfi-llama.git && cd wolfi-llama
</code></pre>
<p>This is the Dockerfile we'll build:</p>
<pre><code>FROM cgr.dev/chainguard/gcc-glibc:latest-dev
RUN apk add cmake --no-cache
WORKDIR /opt/llama
RUN git clone https://github.com/ggerganov/llama.cpp.git && cd llama.cpp
WORKDIR /opt/llama/llama.cpp
RUN cmake -B build -DLLAMA_CURL=OFF && cmake --build build --config Release
ENTRYPOINT ["/opt/llama/llama.cpp/build/bin/llama-server"]
</code></pre>
<p>You can now build the image with:</p>
<pre><code>docker build . -t wolfi-llama
</code></pre>
<p>Please notice the build may take several minutes to finish. When it's done, test with:</p>
<pre><code>docker run --rm wolfi-llama --version
</code></pre>
<p>You'll get output similar to this:</p>
<pre><code>version: 7031 (655cddd17)
built with cc (Wolfi 15.2.0-r5) 15.2.0 for x86_64-pc-linux-gnu
</code></pre>
<p>You're ready to go, but you still need to download the large language model files, which is coming up next.</p>
<h2>Downloading the LLM Files</h2>
<p>There are two files you'll need to download from HuggingFace in order to run the LLMs with Llama.cpp. The main file is the model per se, which is typically a large file - the actual size depends on the number of parameters (values that an LLM learns during training). You can usually choose from a wide range of model sizes like 2B, 8B, 32B and others, where 'B' stands for billions, not the size of the file but still directly related. Larger models produce improved results, but take much longer to run. For models with vision capabilities (which is the case for Qwen3-VL), you'll typically need also a <code>mmproj</code> file as well, which works as some sort of bridge between language and image understanding. Without this file, Qwen3-VL can't process images.</p>
<p>You can find <a href="https://huggingface.co/collections/unsloth/qwen3-vl">here</a> a list of Qwen3-VL models available for download on Huggingface. For the Raspberry Pi, this <a href="https://huggingface.co/unsloth/Qwen3-VL-2B-Instruct-GGUF">2B Instruct version of Qwen3-VL</a> looks like the best option.</p>
<p>The <a href="https://huggingface.co/unsloth/Qwen3-VL-2B-Instruct-GGUF/tree/main">Files and versions</a> tab contains the actual model files you can download. Understanding the different types can be difficult at first, so let's just download the <a href="https://huggingface.co/unsloth/Qwen3-VL-2B-Instruct-GGUF/blob/main/Qwen3-VL-2B-Instruct-Q8_0.gguf">2B-Instruct-Q8_0</a> version as it's what worked well for me :)</p>
<p>From the terminal on your Raspberry Pi (or in your computer), download the main model file:</p>
<pre><code>curl -L -O https://huggingface.co/unsloth/Qwen3-VL-2B-Instruct-GGUF/resolve/main/Qwen3-VL-2B-Instruct-Q8_0.gguf?download=true
</code></pre>
<p>Then, download the mmproj file:</p>
<pre><code>curl -L -O https://huggingface.co/unsloth/Qwen3-VL-2B-Instruct-GGUF/resolve/main/mmproj-F32.gguf?download=true
</code></pre>
<p>Place these files in the <code>models</code> folder from the demo repository you cloned earlier:</p>
<pre><code>mv ~/Downloads/*.gguf ./models
</code></pre>
<p>Now you are all set to run Llama.cpp with the Qwen3-VL model.</p>
<h2>Running the Llama Server</h2>
<p>With everything in place, you can now run your local LLM server. Llama.cpp has a few different executables, but running the <code>llama-server</code> is the most straightforward way of interacting with the LLM since it has a web interface similar to ChatGPT with a prompt and the ability to attach images and other files.</p>
<p><a href="https://docs.unsloth.ai/models/qwen3-vl-how-to-run-and-fine-tune">This page</a> from the Unslolth docs has recommended settings for best results. We'll include them as parameters to the <code>llama-server</code> entrypoint.</p>
<p>Based on those and other docs, and after testing various settings, this is what I used on the Raspberry Pi to bring up the llama-server with a port redirect, using volumes to share the model files with the container:</p>
<pre><code>docker run --rm --device /dev/dri/card1 --device /dev/dri/renderD128 \
-v ${PWD}/models:/models -p 8000:8000 wolfi-llama:latest --no-mmap --no-warmup \
-m /models/Qwen3-VL-2B-Instruct-Q8_0.gguf --mmproj /models/mmproj-F32.gguf \
--port 8000 --host 0.0.0.0 -n 512 \
--temp 0.7 \
--top-p 0.8 \
--top-k 20 \
--presence-penalty 1.5
</code></pre>
<p>It may take a few seconds to the server to start up. You should see logs like this when it's ready:</p>
<pre><code>main: server is listening on http://0.0.0.0:8000 - starting the main loop
srv update_slots: all slots are idle
</code></pre>
<p>You can now head to your browser and access your Raspberry Pi's IP address on port <code>8000</code> to access the LLM chat. You'll get a page like this:</p>
<p><img src="llama-server.png" alt="Screenshot showing the web interface for llama.cpp server, with a prompt and saying "How an I help you today?"" /></p>
<p>For instance, I will ask it to describe a picture of my dog for someone with low vision. Processing images takes a lot of tokens, so this may take several secons to complete, but it does work at the end. The size of the image makes a big difference in prompt proccessing time, so it's best to size down and lower the quality of the image to make it smaller before uploading it.</p>
<p><img src="prompt.png" alt="Screenshot of the chat with llama.cpp showing a picture of a dog and a very accurate description that says "This is a close-up photograph of a black French bulldog lying on a grey, ribbed fabric couch. The dog has a short, smooth coat and is looking directly at the camera with wide, dark eyes. It has a distinct facial structure with a wrinkled forehead and small, erect ears. A small patch of white fur is visible on its chest. The dog is holding a pink plush toy in its front paws; the toy is somewhat worn and appears to be a doll or a bear. The background is softly blurred, keeping the focus on the dog and the toy."" /></p>
<blockquote>
<p>This is a close-up photograph of a black French bulldog lying on a grey, ribbed fabric couch. The dog has a short, smooth coat and is looking directly at the camera with wide, dark eyes. It has a distinct facial structure with a wrinkled forehead and small, erect ears. A small patch of white fur is visible on its chest. The dog is holding a pink plush toy in its front paws; the toy is somewhat worn and appears to be a doll or a bear. The background is softly blurred, keeping the focus on the dog and the toy.</p>
</blockquote>
<p>With 2B instructions, the result is very good in my opinion and I think there's no way I would detail the picture so much if I was going to describe it myself.</p>
<p>But I was curious to see what a larger version of the model would produce, so I got the 32B version of this model and run it with the same prompt and picture on my 128GB/32CPU PC (it was slooooow):</p>
<p><img src="32b-output.png" alt="Output produced by 32b model: "This image features a small, dark-colored French Bulldog lying comfortably on a soft, ribbed gray couch. The dog has large, expressive, round eyes that appear alert and curious, and its ears are perked up, adding to its attentive expression. The dog’s coat is mostly black or dark brindle, with a small patch of white fur on its chest. Its mouth is slightly open, revealing a few small teeth, giving it a playful or slightly grumpy look. In front of the dog, resting on the couch, is a pink plush toy that resembles a small creature or bear. The toy has a fuzzy, textured pink body and a light beige face with large, round blue eyes, a small pink nose, and a black mouth. The toy appears worn and well-loved, suggesting it’s a favorite plaything. The overall scene feels cozy and warm, with the dog appearing relaxed and content in its home environment, possibly enjoying a quiet moment with its favorite stuffed companion. The couch fabric has a vertical ribbed texture that adds depth and softness to the background."" /></p>
<blockquote>
<p>This image features a small, dark-colored French Bulldog lying comfortably on a soft, ribbed gray couch. The dog has large, expressive, round eyes that appear alert and curious, and its ears are perked up, adding to its attentive expression. The dog’s coat is mostly black or dark brindle, with a small patch of white fur on its chest. Its mouth is slightly open, revealing a few small teeth, giving it a playful or slightly grumpy look. In front of the dog, resting on the couch, is a pink plush toy that resembles a small creature or bear. The toy has a fuzzy, textured pink body and a light beige face with large, round blue eyes, a small pink nose, and a black mouth. The toy appears worn and well-loved, suggesting it’s a favorite plaything. The overall scene feels cozy and warm, with the dog appearing relaxed and content in its home environment, possibly enjoying a quiet moment with its favorite stuffed companion. The couch fabric has a vertical ribbed texture that adds depth and softness to the background.</p>
</blockquote>
<p>It's very interesting to see the difference between model versions. It really looks like there's more reasoning (or interpretation?) on the 32B model, but the 2B model is much more lightweight and produces solid enough results for ALT descriptions. You'd need a lot more processing power than what is available at a Raspberry Pi 5 to run those!</p>
<h2>Conclusion</h2>
<p>Getting involved with LLMs in the context of open source goes much beyond prompt engineering and vibe coding; it's about finding the edge cases where LLMs can really be useful for humans. Accessibility is a great example of legit application of computer vision in LLMs. In terms of privacy concerns, running everything in your own infrastructure gives your power back, since you can even block access to external networks and keep your LLMs completely offline.</p>
<p>While many expect that "the AI bubble will soon burst", I believe it's a good idea to get involved and try these tools for yourself to understand how they work. Without massive involvement of the open source community, we let private organizations dictate where the technology goes, and we don't really want that.</p>
Erika HeidiFreeCAD 1.0 for Beginnershttps://eheidi.dev/posts/freecad-for-beginnershttps://eheidi.dev/posts/freecad-for-beginnersIn this introduction to 3D design with FreeCAD 1.0, learn the basics about FreeCAD and how to navigate its interface.Thu, 14 Aug 2025 00:00:00 GMT<p>As the name suggests, <a href="https://www.freecadweb.org/">FreeCad</a> is a free and open source CAD software, a parametric modeler that can be used to design 3D objects for printing. It is available for Linux, Mac, and Windows users. Despite being a well established project with over 2 decades of development, it's 1.0 version came out just recently, solidifying FreeCAD as a robust choice for CAD design on all platforms.</p>
<p>In this introduction to 3D design with FreeCAD, you'll learn the basics about the software, some important concepts, and how to navigate the user interface. Then, we'll see step-by-step how to use the Part Design + Sketcher workbenches to create a simple pen holder that can be 3D printed.</p>
<p>If you want to follow along, now is a good time to <a href="https://www.freecadweb.org/downloads.php">get FreeCad installed</a> on your computer before moving ahead.</p>
<h2>FreeCAD Basics</h2>
<p>There are a few concepts you should get acquainted early on:</p>
<ul>
<li><strong>Workbench</strong>: FreeCAD has a series of workbenches for different purposes. Most of the time, though, you'll be working with the <strong>Part Design</strong> and <strong>Sketcher</strong> workbenches.</li>
<li><strong>Sketch</strong>: A sketch is a technical drawing representing an object or part of it. The sketch uses different geometry to represent a part in 2D. Once all wires are closed and you have a valid form, you can turn it into a solid part.</li>
<li><strong>Constrain</strong>: Constrains are the glue to create parametric models. They allow you to assure things such as distance between two points, width / height of a line, diameter of a circle, and so on... constrains support formulas and variables, features that can be used to generate custom models in multiple sizes.</li>
</ul>
<h2>The Interface</h2>
<p>At first sight, FreeCAD's interface may look less intuitive (or too "bare") than other design software you might be used to work with. But once you get familiar with the general concepts of how to work with the interface, how to switch between workbenches, and how to manipulate planes and perspectives, you'll be in a much better position to explore and experiment with different methods for designing objects.</p>
<p><img src="01-freecad-interface.png" alt="FreeCAD's interface" /></p>
<p>Unless you are already used to a different navigation style from another CAD software, I recommend changing the default interface navigation to "Touchpad". To do that, look for the navigation style select box at the bottom right portion of FreeCAD's UI.</p>
<h2>Creating a Simple Solid</h2>
<p>To experiment with the interface, you can create a new model in <strong>File -> New</strong>, then open the <strong>Part</strong> workbench and click on the Cube icon to create a new solid cube.</p>
<p><img src="02-part-cube.png" alt="Creating a new model on FreeCAD" /></p>
<h2>Navigating XYZ</h2>
<p>When designing 3D models, one of the most important things to get used to at first is the <strong>Z</strong> axis, and how to navigate different perspectives.</p>
<p>Most of us are familiar with X and Y, but when designing 3D objects you'll work with a third axis: Z. You'll typically work from a top view of the object you're designing; Z in this case is the axis that represents the depth of the object. In many cases, Z might simply represent the extrusion width. Wait - what is an extrusion? We'll get there in a moment.</p>
<p><img src="03-navigation.gif" alt="Navigating XYZ axis on FreeCAD" /></p>
<p>On FreeCad, you can see the axis position on the bottom right of the screen, and the top right shows a cube with a more user-friendly view of the same information.</p>
<p>Here are the two most important controls, using the Touchpad navigation style:</p>
<ul>
<li><code>SHIFT</code> + Mouse move: Move the object on the screen without changing the perspective.</li>
<li><code>SHIFT</code> + <code>LEFT CLICK</code> + Mouse move. This will move the object freely across different axis. Like you're handling the object in front of you with one hand.</li>
</ul>
<p>Additionally, the zoom controls are:</p>
<ul>
<li>Zoom In: <code>SHIFT</code> + <code>CTRL</code> + <code>+</code> key, or <code>SHIFT</code> + <code>CTRL</code> + Mouse move.</li>
<li>Zoom Out: <code>CTRL</code> + <code>-</code> key, or <code>SHIFT</code> + <code>CTRL</code> + Mouse move.</li>
</ul>
<p>If you "lose" the object, you may use the magnifying glass icon on the top left, and that will fit the whole content on the screen.</p>
<h2>Working with Perspectives</h2>
<p>In most 3D design applications, you'll work with different perspectives that are exhibited in the screen as a 2D image, representing different possible combinations of X, Y, and Z. Depending on the software you use, there might be different shortcuts for accessing default perspectives. On FreeCAD, you can use keys from <strong>0</strong> to <strong>6</strong> to control the perspective:</p>
<ul>
<li><strong>0</strong> : Isometric</li>
<li><strong>1</strong> : Front</li>
<li><strong>2</strong> : Top</li>
<li><strong>3</strong> : Right</li>
<li><strong>4</strong> : Rear</li>
<li><strong>5</strong> : Bottom</li>
<li><strong>6</strong> : Left</li>
</ul>
<p><img src="04-perspectives.gif" alt="Changing Perspective of objects on FreeCAD" /></p>
<p>You can also use the perspective buttons close to the magnifying glass to change the perspective of the model, they essentially do the same thing as the shortcuts.</p>
<h2>Navigating through Workbenches</h2>
<p>Workbenches provide different tools that are grouped to target different design workflows. Some workflows may require the use of multiple workbenches. As an example, the Sketcher workbench is typically used with the Part Design workbench to create parts based on a 2D sketch.</p>
<p>To navigate to a different workbench, you may use the workbench select menu on the top of the screen. You'll notice that the menu tools will change depending on the workbench selected:</p>
<p><img src="05a-workbenches.png" alt="Navigating through Workbenches on FreeCAD: Part Design workbench tools" /></p>
<p><img src="05b-workbenches.png" alt="Navigating through Workbenches on FreeCAD: Draft workbench tools" /></p>
<h2>Saving an STL file</h2>
<p>To save a model as an STL file that you can slice and print with a 3D printer, you first need to select the object you want to export, from the "Model" view on the left navigation sidebar, and then go to <strong>File</strong> -> <strong>Export</strong> menu. Make sure to select "STL Mesh" on the file type.</p>
<p><img src="06-saving-stl.gif" alt="Saving an STL file on FreeCAD" /></p>
<h2>Next Steps</h2>
<p>You learned the basics of how to navigate FreeCAD's interface, how to move between workbenches, and how to create a simple solid in the Part design and export the STL mesh for 3D printing. In the next post of this series, you'll learn <a href="/posts/freecad-tutorial-penholder">how to create a simple pen holder using FreeCAD's Part Design and Sketcher workbenches</a>. Check also the <a href="https://wiki.freecad.org/Main_Page">FreeCAD wiki</a> in case you want to learn more about FreeCAD.</p>
Erika HeidiMinecraft for Busy Grown Upshttps://eheidi.dev/posts/minecraft-introduction-for-busy-grownupshttps://eheidi.dev/posts/minecraft-introduction-for-busy-grownupsA complete guide to get started quickly playing Minecraft with family and friendsSat, 01 Feb 2025 00:00:00 GMT<p>Whether or not you have kids, there is a high chance you have heard about Minecraft. The pixelated look with characters made out of blocks became an iconic brand that most people recognize even if they have never played the game before.</p>
<p>Minecraft was originally released in 2011 by Mojang Studios, with Microsoft buying the brand later on in 2014. It has since become the <a href="https://en.wikipedia.org/wiki/List_of_best-selling_video_games">best-selling video game of all time</a>, with over 300 million copies sold. Often cited as one of the greatest video games ever created, Minecraft is also often used in <a href="https://www.gamespot.com/articles/minecraft-in-education-how-video-games-are-teaching-kids/1100-6400549/">educational environments</a> as a tool to teach geography, chemistry, programming, among other subjects. There's even a <a href="https://en.wikipedia.org/wiki/A_Minecraft_Movie">movie</a> to be released this year!</p>
<p>There are many different ways in which you can play Minecraft, but overall, Minecraft is a lovely game to play online with friends and family. In this straightforward guide, I will share what I learned as a newbie parent gamer setting up Minecraft worlds to play with my daughter and her friends. I won't go into too many details about how to play the game, just enough so that you can start building and exploring your Minecraft worlds.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/minecraft_boredcatmom.png" alt="A view from one of our many houses in our Minecraft World" /></p>
<p>If you'd prefer a video introduction to Minecraft, check <a href="https://www.youtube.com/watch?v=usdY6BO_QLc&list=PL0D32haHBErz-CxrNwOpWQJJpam0pPqNC&index=1">The Bored Cat Family</a> on YouTube, where I share the most important bits to get started quickly.</p>
<h2>TL;DR</h2>
<ul>
<li>There are two main versions of Minecraft: Bedrock and Java. Bedrock runs on consoles, Android and iOS, and on Windows systems, while Java runs on macOS, Linux, and Windows. These are not compatible with each other, so you have to choose depending on your available devices. Bedrock is the most versatile and multi-platform.</li>
<li>You'll need to buy Minecraft, either from their website (for PC) or from your game console digital store (PlayStation, Nintendo Switch, Xbox…). On Windows, it is possible to play both Java and Bedrock. Minecraft is also available for Android and iOS devices and can be played on mobile.</li>
<li>Playing with remote friends in a shared world requires a Minecraft server or a Minecraft Realm. Setting up a server can be lots of work, but more folks can join. Realms are managed instances with a limited number of concurrent players (up to 11), they are easy to set up and require no maintenance. There are Realms for Java and for Bedrock.</li>
</ul>
<h2>Preparation and Install</h2>
<p>To play Minecraft with friends and family, you will need:</p>
<ul>
<li>A <a href="https://signup.live.com">Microsoft</a> account;</li>
<li>A suitable device that is compatible with the version of Minecraft your friends are playing;</li>
<li>The Minecraft software. If playing on a PC, you'll need to purchase <a href="https://www.minecraft.net/en-us/store/minecraft-java-bedrock-edition-pc">Minecraft Java & Bedrock PC edition</a>. If playing from a console such as Nintendo Switch, Xbox, or PlayStation, you'll need to purchase the game from your console digital store. If playing from a mobile or tablet, you'll need to purchase the game from the Google Play Store or Apple App Store.</li>
</ul>
<p>For people used to working on a PC daily, it might be easier to play the PC version, using your keyboard and mouse. I personally prefer that over playing with a controller. My daughter, on the other hand, finds it easier to play with the controller, since she is not used to keyboard and mouse operation. On tablets and mobile, the game is played with touch controls, which can be a bit tricky and less precise than using a controller or a keyboard and mouse. It's still a good option to play on the go, and also for kids who are used to playing games on mobile and tablets.</p>
<p>There might be some differences in gameplay between devices, and also in the depth of view. In my experience, when playing on a console, the depth of view is limited, and you can't see as far as you can when playing on a PC. Here's a comparison of the depth of view between playing on a console or tablet and playing on a Windows PC with an NVIDIA graphics card (Bedrock edition):</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/minecraft-view-devices.png" alt="view depth differences between playing on a console vs playing on windows PC" /></p>
<h2>Choosing the Right Version</h2>
<p>One thing a lot of people don't realize is that there are different versions of the Minecraft software, and they are not compatible with all devices. The original is the Java version, which is the only version compatible with Linux and macOS systems. The Java version has limitations, but if you don't have a Windows machine you can roll with that one (in this case, everybody else in the group must use the Java version too).</p>
<p>The Bedrock edition runs on consoles and also on Windows computers, Android and iOS devices. This version is the most widely compatible version of Minecraft at the moment, since folks can join from Nintendo Switch, PlayStation, Xbox, mobile and tablets, and also from a Windows PC.</p>
<h3>Minecraft Compatibility Matrix</h3>
<p>Before opting for a platform, it's good to know which platform your friends are playing on, so that you can make sure you're purchasing a compatible version. Overall, Bedrock is preferred, since it is compatible with more platforms, but that will require you to use Windows if you're playing on a PC. I haven't tried running Minecraft from a virtual machine, so I do not know if that is possible at all. Here at home, I play on an older Windows notebook, while my daughter plays on her Nintendo Switch.</p>
<table>
<thead>
<tr>
<th></th>
<th>Windows</th>
<th>Linux / macOS</th>
<th>Consoles</th>
<th>Android and iOS</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Windows</strong></td>
<td>Java and Bedrock</td>
<td>Java only</td>
<td>Bedrock only</td>
<td>Bedrock only</td>
</tr>
<tr>
<td><strong>Linux / macOS</strong></td>
<td>Java only</td>
<td>Java only</td>
<td>X</td>
<td>X</td>
</tr>
<tr>
<td><strong>Consoles</strong></td>
<td>Bedrock only</td>
<td>X</td>
<td>Bedrock only</td>
<td>Bedrock only</td>
</tr>
</tbody>
</table>
<h2>Understanding Minecraft Worlds, Servers, and Realms</h2>
<p>The first thing you need to understand about the Minecraft experience is that the game happens in a sandbox world, and you can have several worlds with different patches and mods applied. Mods can change the basic gameplay and introduce different animals, textures, and functionalities. Be aware that some texture packs modify the basic behavior of the game, which disables the ability to earn achievements. Starting with the vanilla version is a good idea, so you can get acquainted with the basic gameplay and controls.</p>
<p>Worlds can be played offline, but it's not all that much fun to play by yourself. To be able to invite friends over to your world so that you can play in a private, shared environment, you'll need either a Minecraft Server or a Minecraft Realm.</p>
<h3>Playing with Friends</h3>
<p>To play with friends in a shared world, you'll need a Minecraft Server or a Realm. The Minecraft server software is available for both <a href="https://www.minecraft.net/en-us/download/server">Java</a> and <a href="https://www.minecraft.net/en-us/download/server/bedrock">Bedrock</a> editions. Be aware that running and managing your own server has costs and can be lots of work! <a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-minecraft-server-on-ubuntu-22-04">This tutorial on DigitalOcean</a> explains in detail how to install the Java server and get it up and running on a Linux VPS.</p>
<p>For those who don't want to deal with servers and maintenance, <a href="https://www.minecraft.net/en-us/realms">Minecraft Realms</a> can be just the perfect solution – these are managed instances where you can play with up to 10 friends simultaneously, upon invitation. At a monthly cost of $3.99 for 3 simultaneous players (you + 2 players) and $7.99 for 11 simultaneous players (you + 10 players), this option is usually still cheaper than paying for a remote server and getting it set up on your own. Be aware that there are two different versions of Realms, one for Bedrock (Minecraft Realms and Realms Plus) and one for Java (Minecraft Java Realms), so make sure to choose a version compatible with your devices if you are subscribing to this service.</p>
<p>Lastly, there are public servers where you can play with people from all over the internet. Naturally, these are not under your control, so you have to choose a server very carefully if you're playing with your kids. <a href="https://findmcserver.com/">This site</a> has the official Minecraft server list presented by Gamersafer, where servers are classified and identified with badges so you can find a suitable server more easily.</p>
<h2>Getting Started</h2>
<p>When playing on a PC, you'll open the <strong>Minecraft Launcher</strong> in order to start the game. The first time you click on the green "PLAY" button on the top, it will download the game to your computer. The launcher detects your operating system and will only allow you to run compatible versions of the game.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/launcher.png" alt="Minecraft game launcher for PC" /></p>
<p>When the download is complete, the game will launch in a new window.</p>
<h3>Minecraft Bedrock Edition</h3>
<p><img src="https://cdn.erikaheidi.com/minecraft/01-initial-screen.png" alt="Initial screen Minecraft Bedrock Edition" />
Bedrock edition runs on consoles and also on Windows systems. One of the main differences between Bedrock and Java is that on Bedrock you have access to the <a href="https://www.minecraft.net/en-us/catalog">Minecraft Marketplace</a>, where you can get customizations for your character and for your Minecraft worlds. After signing in with your Microsoft account, you'll be able to change the appearance of your character and also edit your profile on Minecraft, directly from the game interface.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/04-marketplace.png" alt="Minecraft marketplace for Bedrock edition" /></p>
<h3>Minecraft Java Edition</h3>
<p><img src="https://cdn.erikaheidi.com/minecraft/01-java.png" alt="Initial Screen Minecraft Java Edition" /></p>
<p>The Java edition opens in a screen where you can choose between Singleplayer or Multiplayer modes, and there's another option to access Minecraft Java Realms. The multiplayer mode allows you to connect to Minecraft servers both remotely and also on your local network. To be honest, I haven't tried to connect to a remote server as I did not know any, and also because I wouldn't be able to play with my daughter anyway, since she is playing on the Switch (Bedrock edition). You can definitely <a href="https://www.digitalocean.com/community/tutorials/how-to-create-a-minecraft-server-on-ubuntu-22-04">install your own Minecraft server</a> and invite your friends, but only folks playing the Java version will be able to join. If you don't want to manage a whole server on your own, you can also subscribe to Minecraft Java Realms and create a realm there for a fee. Again, only folks playing the Java version will be able to join, so think it through before you spend money on a Minecraft Java Realm.</p>
<h2>Minecraft Game Modes</h2>
<p>As mentioned briefly in the introduction, Minecraft has essentially 3 different modes in which you can play with friends. The mode is set for a world as a whole, so everyone playing in that world will be subject to the same type of gameplay.</p>
<h3>Survival Mode</h3>
<p><img src="https://cdn.erikaheidi.com/minecraft/mobs.jpg" alt="creepers in a cavern" /></p>
<p>This is the classic, default mode of playing Minecraft. In survival mode, you have to mine blocks to build everything from scratch – including tools. You can choose from 4 different difficulty levels: peaceful, easy, normal, and hardcore. In survival mode, hostile <a href="https://beebom.com/minecraft-mobs-complete-list/">mobs</a> will spawn at night, and they can hurt you and destroy your buildings. You also need to eat food, otherwise you'll starve to death.</p>
<p>If you want the excitement of mining and building your world from scratch but don't want to deal with mobs and food, you can choose "Peaceful" mode, and nothing will harm you. You can still get hurt in other ways, like falling from a high, but mobs won't spawn at night, and you don't need to eat. This is an excellent way to get started and learn how to play the game, how to build your tools, and where to find resources. I definitely recommend Peaceful Survival mode for anyone who is starting, and also for those who prefer a more chill gameplay. Just be aware that some resources and materials are only available from mobs, so you'll need to switch to a higher difficulty level if you want to get those resources.</p>
<p>In hardcore mode, you only have one life, and if you die, you lose everything. This is a good mode for experienced players who want a challenge.</p>
<h3>Creative Mode</h3>
<p>In this mode, you don't need to mine or build things, because you'll have infinite resources directly available from your inventory. You can also fly, which makes things a lot easier for building. This mode is good for building big worlds and creating experiences for other users, or to simply build grand things without having to collect all the materials you'd normally need.</p>
<p>I confess that I started playing creative mode because I was too lazy, but I quickly became bored, because there was no goal or progression. Nowadays, I prefer Survival mode, where I get all the excitement of mining new materials and building things from scratch. I have played a lot in Peaceful mode to avoid the annoyance of hostile mobs, but it is more fun to play in Easy or Normal mode, where you have to be careful and plan your moves.</p>
<h3>Adventure Mode</h3>
<p>In Adventure mode, you don't build or mine anything; this is a special mode that allow users to experience Minecraft in a more storytelling way. In this mode you can still take damage, and you can interact with redstone mechanisms and also trade with villagers. These features are often leveraged by users to build worlds with custom experiences and mini-games. Many of these worlds can be found at the <a href="https://www.minecraft.net/en-us/catalog">Minecraft Marketplace</a> under "Adventure Maps".</p>
<h2>Playing the Game</h2>
<p>Enough talking, now let's see the basics about how to play Minecraft.</p>
<h3>Character Customization</h3>
<p>Before you start playing, you may want to customize your character. On Bedrock edition, you can do so directly from the game, and you can also purchase custom skins and clothes from the Marketplace.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/03-character.png" alt="Customizing Character in Bedrock edition" /></p>
<p>On Java edition, you need to access your profile in the Minecraft website, and access the menu "Change Skin" in the <em>Minecraft: Java Edition</em> section. In this menu, you can upload custom skins in PNG format. You can find a <a href="https://www.minecraftskins.com/">large collection of downloadable skins in this website</a>.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/03-character-java.png" alt="Customizing Character in Java edition" /></p>
<h3>Creating an Offline World</h3>
<p>The best starting point to get acquainted with the gameplay and controls is by creating a new offline world that can serve as your sandbox. If you hit the "Create New" button on the main screen, you'll be able to choose the world type, the game mode, and the difficulty level. Give your world a name and hit "Create" to get started. This world will then be listed within your "Worlds" and you can access it offline at any time.</p>
<h3>Joining a Realm</h3>
<p>If you have an invitation for a Realm, or if you have subscribed to Realms, you can play online with friends by joining the Realm.</p>
<p><img src="https://cdn.erikaheidi.com/minecraft/05-realms.png" alt="Joining a Realm" /></p>
<h3>Basic Controls</h3>
<p>When playing on a computer, you can move with the keys <strong>a</strong>, <strong>w</strong>, <strong>s</strong>, <strong>d</strong>. Left mouse click will mine or hit an object, while right mouse click is for placing and interacting (for instance, in the craft table). Moving the mouse moves the camera. To drop an item, use the <strong>q</strong> key. The inventory is available with the <strong>e</strong> key. To run, typically you'll double-tap the <strong>w</strong> key.</p>
<p>When playing on a console, you'll typically use the "ZR" button for mining and hitting, while the "ZL" button will be for placing items and interacting with items. Left stick for moving, right stick for moving the camera view. Main action button to jump, and second action button to crouch. Running is usually done by pressing the left stick.</p>
<p>When playing on Android or iOs, you can move by dragging your finger on the screen, and you can interact with objects by tapping on them. It is also possible to connect a controller or a keyboard and mouse to your mobile device to play Minecraft. I have tried this with my Android tablet and it works well, although I still prefer playing on the PC for a better depth of view.</p>
<p>You'll be working a lot with your inventory and in your craft table. Use the search feature to search for recipes when you want to craft something specific. New recipes will unlock as you discover new materials.</p>
<h2>The Minecraft World</h2>
<p>Now that you have your character set up and you know how to move around and interact with objects, it's time to explore the world. The Minecraft world is vast and full of resources, and you can build and mine almost anything you can imagine! There's a lot to do ande to explore. Let's learn some basics to help you get started in the best possible way.</p>
<h3>Biomes and Spawn Points</h3>
<p>As worlds are randomly generated, your spawn place (or the place where you'll land when you join the game) is typically determined at random, and you can end up in any of the available <a href="https://minecraft.fandom.com/wiki/Biome">biomes</a> depending on how your world map was generated. When creating the world, is also possible to choose from a list of templates that determine a preferred location as world spawn point.</p>
<p>Minecraft biomes separate worlds into different environments, such as desert, mountains, beach, forest, and more. Each biome has its own geographical features and resources. If you are not satisfied with where you landed, you can always migrate to another area. Just keep moving in the same direction, and you'll definitely find a different biome where you can live!</p>
<p>When you sleep in a bed, a new spawn place is set, so you will always return to your "new home". If you migrate, make sure to find a spot where you can craft a bed so you don't go back to the original spawn location in case you die and respawn.</p>
<h3>Villages and Structures</h3>
<p>In addition to biomes, you'll also find villages and other structures in the world. Villages are populated by villagers, which are neutral mobs that can trade with you. You can also find temples, dungeons, and other structures that contain valuable resources and treasures. Exploring the world is a good way to find new materials and recipes. Just be careful with hostile mobs that can spawn in dark places, such as caves and dungeons.</p>
<p>If you're lucky enough to find a village close to the world spawn point, that is an excellent first place to build a base. You'll find food and other resources, and you can also trade with villagers. Villages are also a good place to find a bed, so you can set your spawn point and avoid going back to the original spawn location.</p>
<h3>Mining and Crafting</h3>
<p>Mining is the main activity in Minecraft. You'll need to mine blocks to get resources, and then you'll use these resources to craft tools, weapons, and buildings. The game has a crafting system that allows you to create new items by combining materials in a specific pattern. You can craft a variety of items, from tools to weapons, armor, and even food. The crafting system is very intuitive, and you can use the search feature to find recipes for items you want to craft.</p>
<p>The first thing you'll need to do is to mine some wood. You can punch trees to get wood blocks, and then you can use these blocks to craft a <strong>crafting table</strong>. With the crafting table, you can craft more items and tools. You'll need to mine stone to craft better tools, and you'll need to mine iron to craft even better tools and armor. The game has a progression system that allows you to unlock new recipes as you discover new materials.</p>
<h3>Hostile Mobs</h3>
<p>Minecraft has a variety of hostile mobs that can hurt you. Most hostile mobs spawn only at night and in dark places, and some of them burn in the sun. When the sun starts to go down, you have to seek shelter to avoid being attacked by mobs. You can also craft torches to light up dark places and avoid mobs from spawning. Some mobs are neutral and will only attack if you attack first. A few of the most common hostile mobs are:</p>
<ul>
<li><strong>Zombies</strong>: slow and weak, but they can spawn in groups and overwhelm you. They burn in the sun, so you can avoid them by staying in the light.</li>
<li><strong>Drowned</strong>: these are basically water zombies. Some of them carry tridents, which can be dangerous, so be careful when swimming in the ocean.</li>
<li><strong>Skeletons</strong>: they shoot arrows at you from a distance, so they can be really annoying.</li>
<li><strong>Creepers</strong>: they explode when they get close to you, so you have to be careful. They can destroy your buildings, so it's best to avoid them or lure them to areas where they can explode without damaging your house. For me, creepers are the worst.</li>
<li><strong>Spiders</strong>: they can climb walls and jump at you, so they can be hard to avoid. They are easy to kill, though. Spiders are neutral during the day, but they become hostile at night.</li>
<li><strong>Endermen</strong>: they are tall and black, with purple eyes. A very enigmatic figure. They are neutral unless you look at them, so it's best to avoid eye contact! It's hard because they are kinda beautiful in a way, you feel like you want to look at them, but you shouldn't. They teleport, so they can go wherever you are and attack you if you stare at them.</li>
<li><strong>Witches</strong>: they throw potions at you and are also quite hard to kill, so it's best to avoid them altogether!</li>
</ul>
<p>Hostile mobs cannot open doors or gates, so you can use these to protect yourself from them. You can also build a wall around your house to keep mobs away. Just be aware that some mobs can spawn inside your house if it's not well lit, so make sure to use plenty of torches. And always keep your doors and gates closed!</p>
<h3>Farming and Breeding</h3>
<p>You can farm animals and plants in Minecraft. You can breed animals to get more of them, and you can also grow plants to get food. To breed animals, you just need to feed them with their favorite food. For instance, you can breed cows with wheat, and you can breed chickens with wheat seeds.</p>
<p>Farming typically requires a <strong>hoe</strong> to prepare the terrain, and you'll also need some water nearby to keep the soil moist. A quick way to build a farm is finding a coastal area, where you can build a farm close to the water. You can also build an irrigation system to keep your farm watered. You can use a bucket to carry water from a water source to your farm, but that requires iron to craft the bucket.</p>
<h2>Things to be Aware - Top Tips</h2>
<ul>
<li>You can mine some things with your bare hands, but you'll typically need a tool that is right for the job in order to be efficient. Some resources can only be mined with specific tools.</li>
<li><strong>Pickaxes</strong> are for mining stone. For wood, you'll need an <strong>axe</strong>. For dirt / soil you'll need a <strong>shovel</strong>. For planting seeds, you need a <strong>hoe</strong>. For shearing wool from sheep, you need <strong>sheers</strong>.</li>
<li>Some materials require a stronger tool to be mined. For instance, you'll need an iron pickaxe for mining gold and redstone.</li>
<li>You can get hurt if you fall from a high, so be careful when going down.</li>
<li>When digging down, be careful to not just dig straight down, create a staircase so you can climb back up.</li>
<li>Many mobs are neutral and will only attack if you attack first. Hostile mobs will always attack.</li>
<li>Always have torches if you're mining down and going into caves. It's very dark down there!</li>
<li>It's good to carry an extra craft table that you can deploy when needed, for instance when you're in a cave and your pickaxe breaks.</li>
<li>If you're unsure where to build your house, try to find a <a href="https://minecraft.fandom.com/wiki/Village">village</a>. Each biome has a slightly different type of village, and they will have resources such as food plantations and you can also trade with villagers.</li>
</ul>
<h2>10 Steps in a new Minecraft World</h2>
<p>This is a suggested roadmap of 10 initial goals to get acquainted with Minecraft and get settled in your new world.</p>
<ol>
<li>Find a good spot to build your house
<ol>
<li>Look at material sources nearby</li>
</ol>
</li>
<li>Collect some wood</li>
<li>Build a crafting table</li>
<li>Craft wood tools</li>
<li>Mine stone</li>
<li>Craft stone tools</li>
<li>Build a house to protect you from the rain
<ol>
<li>You can use stone and wood blocks</li>
<li>Craft a wooden chest to save your stuff</li>
</ol>
</li>
<li>Craft a furnace so you can smelt iron and other materials</li>
<li>Keep mining to find new materials and recipes
<ol>
<li>Find <strong>coal</strong> to build torches so you can dig deeper in the mountains</li>
<li>Find <strong>iron</strong> so that you can craft scissors to cut off wool from sheep (then you'll be able to craft a bed)</li>
<li>Find <strong>sand</strong> to craft glass blocks that you can use as windows</li>
</ol>
</li>
<li>Build a fun rail system to move along your village
<ol>
<li>Collect more <strong>iron</strong> to build rails and a rail cart</li>
<li>Find <strong>gold</strong> to build activated rails</li>
<li>Find <strong>redstone</strong> to move a rail cart through rails</li>
</ol>
</li>
</ol>
<p><strong>Tip:</strong> gold and redstone can usually be found very deep in caves. You'll need to craft an <strong>iron pickaxe</strong> in order to mine these materials.</p>
Erika HeidiDocker Basics for Beginnershttps://eheidi.dev/posts/docker-basics-onepagerhttps://eheidi.dev/posts/docker-basics-onepagerLearn how to use Docker to build and run container images on your local environment.Mon, 20 Jan 2025 00:00:00 GMT<p>Docker is a software used to build and run <a href="https://edu.chainguard.dev/software-security/what-are-containers/">containers</a>. Unlike virtual machines, containers do not emulate an entire operating system, relying on the host OS to provide an isolated filesystem that consumes less resources than traditional VMs, but still provide a fully functional runtime based on a chosen operating system.</p>
<p><img src="https://cdn.erikaheidi.com/blog/container-model-graph.png" alt="The container model as a high-level overview" /></p>
<p>The build steps necessary to (re)create a Docker container image are defined in a <a href="https://docs.docker.com/engine/reference/builder/#dockerfile-reference">Dockerfile</a>. This file may contain special instructions to install packages, create users, and run arbitrary system commands.</p>
<p>Container images can be hosted in a remote registry that allow images to be pulled from different locations. The default Docker registry is <a href="https://hub.docker.com">Docker Hub</a>, but there are many others. When using images from registries other than Docker Hub, you'll need to specify the registry URL along the image identifier.</p>
<h2>Pulling Images from a Registry</h2>
<p>The <code>pull</code> command is used to pull images from a remote registry. It is not mandatory to run this command before running an image, as the pull will happen automatically. However, if you already have a local copy of an image, you'll need to run the <code>pull</code> command in order to obtain an updated version of the image.</p>
<pre><code>docker pull registry/image
</code></pre>
<p>For example, this will pull the <a href="https://edu.chainguard.dev/chainguard/chainguard-images/reference/php">PHP Chainguard Image</a> to your local machine:</p>
<pre><code>docker pull cgr.dev/chainguard/php
</code></pre>
<p>You should see output similar to this:</p>
<pre><code>Using default tag: latest
latest: Pulling from chainguard/php
1e4853eb9712: Pull complete
Digest: sha256:387acb900179de11ca5a56c3ebbb6f29d2df88cb488d50fc9736ab085f27520d
Status: Downloaded newer image for cgr.dev/chainguard/php:latest
cgr.dev/chainguard/php:latest
</code></pre>
<h2>Running Containers</h2>
<p>The <code>run</code> command is used to execute the entry point defined by your image Dockerfile. Depending on the image and how it is used, you may need to provide additional parameters to the command.</p>
<pre><code>docker run registry/image
</code></pre>
<p>For example, the following command will execute the PHP image we pulled in the previous section, with the <code>--version</code> flag to obtain the PHP version:</p>
<pre><code>docker run cgr.dev/chainguard/php --version
</code></pre>
<pre><code>PHP 8.2.12 (cli) (built: Nov 15 2023 15:30:03) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.12, Copyright (c) Zend Technologies
</code></pre>
<h3>Running Containers in Interactive Mode</h3>
<p>Many (maybe even most) container images run a single command and are terminated afterwards. It is the case with regular PHP images that are meant to run scripts. There is no interaction once the process of execution is initiated.</p>
<p>Some images will require some type of interaction from the user. That is often the case with images that run an interactive application such as <code>bash</code>. In those cases, you'll need to provide the <code>-it</code> argument when running Docker:</p>
<pre><code>docker run -it registry/image
</code></pre>
<p>For example, this will execute the <a href="https://edu.chainguard.dev/chainguard/chainguard-images/reference/wolfi-base">wolfi-base</a> image and land you in a shell inside the newly created container:</p>
<pre><code>docker run -it cgr.dev/chainguard/wolfi-base
</code></pre>
<h3>Running Ephemeral Containers</h3>
<p>To remove a container immediately after it is terminated, add the <code>-rm</code> parameter to the <code>docker run</code> command:</p>
<pre><code>docker run --rm registry/image
</code></pre>
<p>This is especially useful for running quick commands that don't generate relevant output that needs to be shared or persisted, as with our first example that checked for the PHP version. We could rewrite that command to the following:</p>
<pre><code>docker run --rm cgr.dev/chainguard/php --version
</code></pre>
<p>And this will prevent Docker from keeping the state of this container, which is good for saving resources.</p>
<h2>Checking Container Status</h2>
<p>To have a full list of active and inactive containers currently registered in the system, run:</p>
<pre><code>docker ps -a
</code></pre>
<p><em>Note: When the <code>-a</code> parameter is not provided, Docker will list only containers that are currently running.</em></p>
<p>You should get output similar to this:</p>
<pre><code>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
26272c21399c cgr.dev/chainguard/php "/bin/php --version" 10 minutes ago Exited (0) 10 minutes ago musing_hermann
</code></pre>
<p>The first time we executed the command to obtain the PHP version of the container, we didn't use the <code>--rm</code> flag. That's why the container is listed here - it's inactive, but its state is saved.</p>
<h2>Using Volume Shares</h2>
<p>When running development environments, it's crucial that you're able to edit your code in your local machine, while being able to execute and test it inside the container. To enable that, you can use <a href="https://docs.docker.com/storage/volumes/">Docker volumes</a>. Volumes are used to share the contents of a predefined path in your host machine to a location inside the container.</p>
<p>The following command will create a volume sharing the contents of LOCAL_FOLDER in the host machine with REMOTE_FOLDER inside the container.</p>
<pre><code>docker run -v LOCAL_FOLDER:REMOTE_FOLDER registry/image
</code></pre>
<h3>Use Case and Example</h3>
<p>Let's say you want to run a PHP script without having to install PHP (could be any other language). You want to be able to make changes to the file and test it in an isolated environment.</p>
<p>Create a folder in your home directory for this demo:</p>
<pre><code>mkdir ~/docker-demo
cd ~/docker-demo
</code></pre>
<p>Next, create a new file and copy the following contents to it:</p>
<pre><code><?php
echo "Testing Docker PHP Dev Env";
print_r($argv);
</code></pre>
<p>Save the file as <code>demo.php</code>.</p>
<p>Now you can use a Docker image to run this code. The following command will create an ephemeral container to execute code shared inside the container:</p>
<pre><code>docker run --rm -v ${PWD}:/app cgr.dev/chainguard/php demo.php
</code></pre>
<p>The <code>${PWD}</code> shell variable contains the current directory location. The volume will share the current directory with the <code>/app</code> location in the container, which is the workdir (the default directory) for that image. With the files shared in the default workdir, you can refer to the script simply as <code>demo.php</code>.</p>
<h2>Purging Docker Resources</h2>
<p>Some resources are not removed once a container is terminated; that is the case with named volumes. Images can also leave a big footprint in your system, think gigabytes of space from unused layers and old images.</p>
<p>The <code>prune</code> command can be used to clean up unused resources and free up space occupied by them. For instance, to purge unused volumes:</p>
<pre><code>docker volume prune
</code></pre>
<pre><code>WARNING! This will remove anonymous local volumes not used by at least one container.
Are you sure you want to continue? [y/N]
</code></pre>
<p>The same logic applies to <code>images</code> and <code>networks</code>. To perform a complete system purge, run:</p>
<pre><code>docker system prune
</code></pre>
<p>You should get a warning message confirming what is going to be removed. Type <code>y</code> to confirm.</p>
<pre><code>WARNING! This will remove:
- all stopped containers
- all networks not used by at least one container
- all dangling images
- all dangling build cache
Are you sure you want to continue? [y/N]
</code></pre>
<p>Unused resources accumulate with time, so it's good to run this command every once in a while. Depending on how you're using Docker, you may be able to free up a lot of disk space with this command.</p>
<h2>Resources to Learn More</h2>
<p>The <a href="https://edu.chainguard.dev/software-security/what-are-containers/">What are Containers?</a> guide from Chainguard Academy has a nice high level overview of containers and images. For more technical specifications and reference docs, check the official <a href="https://docs.docker.com/get-started/overview/">Docker Documentation</a> which covers all components in the Docker container ecosystem.</p>
<p>For considerations about container security, check this Academy guide on <a href="https://edu.chainguard.dev/software-security/selecting-a-base-image/">Selecting a Base Image</a> and the introduction to <a href="https://edu.chainguard.dev/software-security/what-is-software-supply-chain-security/">Software Supply Chain Security</a>, which should give you a better understanding of security considerations when bringing your images to Production.</p>
<h2>Bonus: Docker Cheat Sheet</h2>
<p><img src="https://cdn.erikaheidi.com/blog/docker-cheat-sheet.png" alt="Docker Cheat Sheet" /></p>
Erika HeidiSetting Up Obsidian for Content Planning and Project Managementhttps://eheidi.dev/posts/setting-up-obsidian-for-content-planning-and-project-managementhttps://eheidi.dev/posts/setting-up-obsidian-for-content-planning-and-project-managementObsidian is a flexible markdown writing application that allow users to customize notes with templates and other plugins. In this post, I share my setup and my custom templates for content planning and simple project management.Mon, 11 Mar 2024 00:00:00 GMT<p><em>Originally published on <a href="https://dev.to/erikaheidi/setting-up-obsidian-for-content-planning-and-project-management-38f1">dev.to</a>.</em></p>
<p><a href="https://obsidian.md/">Obsidian</a> is a writing application created to allow for offline / private note taking in markdown format, in an interface that looks a lot like our regular programming IDE. It is very flexible, with a good collection of community plugins that you can use to customize Obsidian to your heart contents.</p>
<p>I recently started using Obsidian at work for daily / weekly notes and it's being super helpful to keep me organized. I am now setting up Obsidian on my personal laptop to help me keep track of ideas and side projects. In this post, I share my setup and my custom templates to facilitate that.</p>
<h2>1. Installing Obsidian</h2>
<p>The first step is to get Obsidian installed on your computer. Check their <a href="https://obsidian.md/download">downloads page</a> to download and install the appropriate version for your system.</p>
<h2>2. Customizing Obsidian Appearance</h2>
<p>Once you get Obsidian installed and when you open it for the first time, you will get a screen like this, asking you to create a new Vault or use an existing directory as vault. A "Vault" is a folder where your markdown documents will live.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dqmcwl0r9h98c5h5gsa4.png" alt="Getting started with Obsidian" /></p>
<p>You can specify where to create your Vault. I created a folder called "My Projects" under my "Documents" and used that. After confirming the location of your Vault, you'll see Obsidian's default interface.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ufwk9w3n6qo1b5anuvm4.png" alt="Obsidian interface" /></p>
<p>I prefer a dark color scheme, so I changed it in <strong>Settings -> Appearance -> Base color scheme</strong>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ap4valpccqvjbjn8rmu1.png" alt="Changing to a dark color theme in Obsidian" /></p>
<p>Further down in the same screen, I increased the interface zoom in <strong>Advanced -> Zoom Level</strong>.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sxhkge8d3gub6coq2val.png" alt="Increasing interface zoom level in Obsidian" /></p>
<p>After that and still on the Settings window, I went to <strong>Community Plugins-> Turn on Community Plugins</strong> to enable community plugins. We'll need this to install some nice plugins that will help us make the most of Obsidian.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/67j9to7i7tx2rdd2gvq0.png" alt="Enabling community plugins on Obsidian" /></p>
<p>At this point, Obsidian is already functional, so you can start creating folders and organizing markdown documents. In the next step we'll install a few plugins to help with content planning and project management.</p>
<h2>3. Installing Templater and Tasks plugins</h2>
<p>Obsidian has a large collection of community-contributed plugins to serve various user needs. For this guide, we'll install <a href="https://github.com/SilentVoid13/Templater">Templater</a> and <a href="https://github.com/obsidian-tasks-group/obsidian-tasks">Tasks</a>, two plugins that can be really powerful when combined to create notes and task lists.</p>
<h3>Templater</h3>
<p><em>It defines a templating language that lets you insert variables and functions results into your notes. It will also let you execute JavaScript code manipulating those variables and functions.</em></p>
<p>We'll use Templater to set up a few default templates per folder. So when you create a new "tutorial" type of content, it will automatically use the designated "tutorial" template. We'll do the same for projects.</p>
<p>First, create a new folder for your templates in your Vault. You can call it "Templates". Then, go to <code>Settings -> Templater</code> and set up the <code>Template folder location</code> to the newly created directory. Also enable <code>Trigger Templater on new file creation</code> .</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gq3z9ziuljmg2343sjx9.png" alt="Setting up Obsidian Templater plugin" /></p>
<p>Now you can start creating templates for different content types, projects, etc, and match each template with a content folder. We'll set up two templates in this guide: <strong>Project</strong> and <strong>Content</strong>.</p>
<p>Create a new file in your Templates folder and call it "Project". You can use the following template as base, customizing it to better fit your needs:</p>
<pre><code>---
name: Project Name
createdAt: <% tp.date.now() %>
description: A project to do X in Z
tags:
- tag1
- tag2
- tag3
---
## To Do
- [ ] Task 01 ⏫
- [ ] Task 02
- [ ] Task 03
## Milestones
- Milestone 1
- Milestone 2
- Milestone 3
## Ideas
- Idea 01
- Idea 02
- Idea 03
</code></pre>
<p>Create another file and call it "Content" - this will be your content template. You can use the following as base:</p>
<pre><code>---
title: How to Do This Thing
description: Learn how to do this thing on Linux
tags:
- tag1
- tag2
- tag3
---
## Introduction
Introduce the thing.
## 1. Doing the first thing
Explain how to do the first step.
## 2. Doing a second thing
Explain how to do the second step.
## 3. Doing a third thing
Explain how to do the third step.
## Conclusion
Quick recap, final remarks, and how to learn more.
---
### Content Launch Checklist
- [ ] Content published to DEV
- [ ] Content shared on X/Twitter
- [ ] Content shared on LinkedIn
- [ ] Short video published on Reels (Instagram)
- [ ] Short video published on YouTube Shorts
- [ ] Long video shared on YouTube
- [ ] Video shared on YouTube
</code></pre>
<p>After setting up both templates, create a "Project" folder to save your project pages and a "Content" folder to save tutorial pages. Then go to <code>Settings -> Templater</code> then navigate to <strong>Folder Templates</strong> to set up the Project and Tutorial content types. You should now associate each folder with its corresponding template.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc5u2cd6jaxrf24pymiu.png" alt="Setting up Obsidian with folder templates" /></p>
<p>After applying the changes, check that everything works as expected by right-clicking on the content or project folder and creating a new note there. The new note should be created using its designated template.</p>
<h3>Tasks</h3>
<p><em>Track tasks across your entire vault. Query them and mark them as done wherever you want. Supports due dates, recurring tasks (repetition), done dates, sub-set of checklist items, and filtering.</em></p>
<p>The Tasks plugin is very powerful because it allows you to create elaborate task lists and search/filter tasks from your whole Vault to be listed in a single document. You can, for instance, list all your TO DO tasks from all your projects, using various filters to surface only what's relevant or high priority.</p>
<p>As you may have noticed in the previous step where we set up Templater templates, we added a <em>TO DO</em> list to the <strong>Project</strong> template and a <em>Content Launch Checklist</em> to the <strong>Tutorial</strong> template. We can surface these tasks on another markdown document that we can use to have a high-level overview of all your open tasks.</p>
<p>Create a new file in the root of your vault and call it "Tasks". Copy the following raw content to this file:</p>
<pre><code>
### Projects
```tasks
not done
filter by function task.file.folder === "Projects/"
```
### Content
```tasks
not done
filter by function task.file.folder === "Content/"
```
</code></pre>
<p>Now when you change from <strong>editing</strong> mode to <strong>reading</strong> mode, you'll get two lists with your TO DO tasks from the "Projects" folder and the "Content" folder, similar to this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rouj0qavzntad8ygt8v9.png" alt="Showing all TO DO tasks in Obsidian" /></p>
<p>You can create multiple pages like this with different search filters to give you complete visibility on your plans and tasks. Here I also created a "Completed Work" page to show tasks that are marked as "done". For that, you can use a simple query like the following:</p>
<pre><code>```tasks
done
```
</code></pre>
<p>Check the <a href="https://github.com/obsidian-tasks-group/obsidian-tasks">Tasks plugin documentation</a> to learn more about the powerful search features provided by the plugin.</p>
<h2>Final Considerations</h2>
<p>Obsidian is a powerful text writing application that allows users to customize it to their very specific needs. With a few plugins, you can turn your Obsidian into a powerful helper to plan and track content, new ideas, and projects.</p>
<p>In this guide we saw how to create a basic setup using the Templater and Tasks plugins to help you track your tasks for content creation and other projects in general. Based on what you learned here, you can further customize your folders and templates in a way that best suits your needs.</p>
Erika HeidiFrom SVG to 3D Printed with Inkscape and FreeCADhttps://eheidi.dev/posts/from-svg-to-3dprinted-with-freecadhttps://eheidi.dev/posts/from-svg-to-3dprinted-with-freecadLearn how to import an SVG file on FreeCAD and turn it into a solid shape that can be 3D printedMon, 20 Nov 2023 00:00:00 GMT<p>In my <a href="/3D-Printing/20231109_freecad-for-beginners">FreeCAD for Beginners</a> article, we built a pen holder using the Sketcher + Part Design workbenches. In this guide, you'll learn how to import an SVG file and transform it into a shape that can be printed or fused into a 3D model.</p>
<p>To pack in more useful tips, I'll also include how to create an original SVG file from a shape found on the web, using Inkscape. You can skip step 1 if you already have a simple SVG file that you plan on using, but it's useful to learn how to create your own shapes using a software like <a href="https://inkscape.org/">Inkscape</a>. This will give you a lot of freedom when designing your original objects.</p>
<h2>Step 1: Preparing the SVG file</h2>
<p>Ideally, your SVG file should have a single shape. If your SVG has multiple shapes, or a hole inside the shape, you'll need to think through each form separately, creating the individual shapes and using the appropriate boolean operations on FreeCAD to get to the result you want. For instance, something with the form of a letter "A" would need an outside shape that would get padded, and another shape to make a pocket or a boolean operation (difference) to remove that portion from inside.</p>
<p>In this guide, we'll create an SVG file from scratch using Inkscape. Inkscape is a free and open source graphics software that can be used to create vectorized images and export them as SVG and other formats.</p>
<p>For this example, we're gonna use <a href="https://en.wikipedia.org/wiki/Rebel_Alliance">Star War's Rebel Alliance logo</a>, because it's a rather simple shape and of course also because it's pretty cool:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yas6yt3bmsrinl2onqow.png" alt="Star Wars Rebel Alliance Logo. source: Wikipedia" /></p>
<p><em>Source: Wikipedia</em></p>
<p>Download the PNG file and open it with Inkscape. In the left tool bar, you'll find the vector tool. It's the one right below the pencil. Use it to draw a vector over the shape:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ou6th9jalqqik9q70n4a.gif" alt="Step 1: Start drawing a vector over the shape" /></p>
<p>After the initial shape is done, you will probably need to adjust some things. Use the node selection tool (the second tool from top to bottom) to adjust the shape to look more like the original.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0hr4eibjbf84z59m9t7c.gif" alt="Step 2: Adjust the shape to match the original" /></p>
<p>Once you're satisfied, delete the base PNG shape and set the fill color of your vectorized shape to black or any other color. Then, save the file as SVG.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ujd6s3nv68ekudcdook9.gif" alt="Step 3: Save the SVG file" /></p>
<p>Can't get the shape right? No worries, vectorizing can be tricky if you are not used to it (but totally worth practicing). You can create a simpler shape using the geometric tools on the left (a square or a circle, for instance, if you just want to practice), or you can <a href="https://erikaheidi.ams3.digitaloceanspaces.com/design3d/rebel_aliance_logo_by_erika.svg">download my own SVG version of this logo in this link</a>. Disclaimer: it's not perfect.</p>
<h2>Step 2: Importing SVG on FreeCAD</h2>
<p>Now, let's go to FreeCAD. To get started, you'll need to open the pen holder source file that we created in the previous tutorial of this series. In case you don't have that file available to you now, you can <a href="https://erikaheidi.ams3.digitaloceanspaces.com/design3d/freecad_penholder_v01.zip">download this FreeCAD project file</a> containing the base penholder object and get started from there. When prompted, select "SVG as Geometry (ImportSVG)" in the dialog box that will appear.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ou5ko4klo0ohneodz11l.gif" alt="importing the svg file into FreeCAD" /></p>
<p>This shape is not an actual solid yet on FreeCAD; it is just a path. We'll now move to the "Draft" workbench, where we can turn this path into a sketch. First, we'll use the "Upgrade Shape" tool, which looks like an arrow pointing upwards.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp7wjv6ase23cd7ad1d2.gif" alt="Moving to the Draft Workbench and Upgrading shape" /></p>
<p>Then, we'll transform this path into a sketch, using the "Draft to Sketch" tool. This tool has an icon with red and blue shapes.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/idlootpa25ssvgk3zk19.gif" alt="Converting draft to sketch" /></p>
<p>You'll notice that a new sketch was created. This sketch's path might not coincide with the positioning of the original path, and that's OK, we'll move it around once we have a solid part. Working with this shape in a separate body will be an easier approach, then we can fuse both parts together later on.</p>
<p>We'll create a new body, using the "Create New Body" icon on the top tool bar (Part Design Workbench) and move this sketch to it.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rwp0rlynzn5z3ajikuve.gif" alt="creating a new body" /></p>
<p>Then, we'll use the "Pad" tool from the top tool bar to pad this sketch into a solid.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/73trzwc6ut4f8jpuo298.gif" alt="Using the Pad tool" /></p>
<p>You now have a solid shape that is already printable. Next, we'll adjust the size and positioning so that we can "glue" this shape on the existing pencil holder.</p>
<h2>Step 3: Adjusting Position and Size</h2>
<p>Finally, we need to adjust the position and size of the logo so that it fits the external wall of the pen holder. Repositioning and resizing on FreeCAD sometimes can be tricky, so I typically use a combination of different methods to reach the positioning I want. For this example, I used all of these:</p>
<h3>Manually Configuring Placement</h3>
<p>You can set the placement of an object using the "Placement" dialog that can be accessed by selecting the object, then going to the left bottom panel where you find the object settings including positioning.</p>
<p>In the dialog window that opens up, you can make rotations to the object around the various axis. In my case, I only wanted to move the orientation so that the logo was in the same orientation as the pen holder walls. I changed the X axis to -90 ant that gave me what I wanted.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uin2dv62o0onkwd7jqo2.gif" alt="Manually moving the logo via object settings - placement" /></p>
<h3>Resizing a Shape in the Draft Workbench</h3>
<p>The easiest way I found to resize a shape is to go to the Draft workbench, and use the "Resize" tool. This will in fact generate a clone shape that is a solid and you can use in boolean operations (essentially, what we want). To use that tool, first select the object, than go to the menu "Modification -> Resize". Click on the object again when asked, then a new dialog will show the proportions. Here, I resized to 0,3 (33% or the original size).</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hsh2y7z5hifntj0auz9t.gif" alt="Resizing a shape in the Draft Workbench" /></p>
<p>Once the clone is created, you can use the "Transform" tool to move and position the logo exactly how you want it.</p>
<h3>Visual Repositioning via "Transform"</h3>
<p>The "transform" tool allows you to move shapes more visually, using a set of arrows that represent all axis. Double-click the shape to access the "transform" controls. You can also move a whole body with the transform tool, by right-clicking the body name at the project list, and clicking on "transform" on the menu that will show up.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1fv7niax3m41pc6lwg7s.gif" alt="Using the Transform tool" /></p>
<h2>Step 4: Fusing Shapes in the Part Workbench</h2>
<p>We have our model almost ready now, the only thing left to do is to fuse both parts together. Go to the "Part" Workbench, select the first body (pen holder base) and the cloned, resized version of the logo (it should have an icon that looks like a sheep). Select the "Union" button on the workbench tool bar on the top (the icon looks like two blue circles). Hit "apply" to confirm, and you'll have now the finished model (fusion resulting object).</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbvt702ul0e6wh3sgkor.gif" alt="Fusing Shapes in the Part Workbench" /></p>
<h2>Printing the Model</h2>
<p>You can now export this model to STL and slice it for 3D printing. To export, select the "fusion..." object that was generated in the final step, then go to "File -> Export". Select STL and save the file. You can now open this file with a slicing software.</p>
<p>This is the final result as printed with our Prusa MK3S:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kh47270dkptz4plmmzl3.jpg" alt="Final result after 3D Printed" /></p>
<h3>Print Specs</h3>
<ul>
<li>0.20mm layer height</li>
<li>10% infill</li>
<li>Filament: Prusament PLA (Galaxy Black)</li>
<li>No supports, no brim</li>
</ul>
<p>If all you want is the final STL file to print, you can <a href="https://www.printables.com/model/439574-star-wars-rebel-aliance-pen-holder">download this model for free on my Printables profile</a>.</p>
Erika HeidiAn Introduction to 3D Printinghttps://eheidi.dev/posts/introduction-to-3d-printinghttps://eheidi.dev/posts/introduction-to-3d-printing3D printing refers to a variety of processes in which a computer-operated machine creates three dimensional objects by joining or solidifying material, typically layer-by-layer until the whole object is complete.Wed, 01 Nov 2023 00:00:00 GMT<h2>Introduction</h2>
<p>3D printing refers to a variety of processes in which a computer-operated machine creates three-dimensional objects by joining or solidifying material, typically layer-by-layer until the whole object is complete. 3D printing is also commonly referred to as <em>additive manufacturing</em>.</p>
<p>Even though the early years of the technology seemed to regard 3D printing as an expensive process only suitable for aesthetical prototypes, the technology behind additive 3D printing has evolved to an impressive scale in the last few years, lowering barriers and making it more popular and affordable to end-users.</p>
<h2>Why 3D Printing</h2>
<p>What first got me into 3D printing was my interest in <a href="https://dev.to/erikaheidi/a-primer-on-basic-electronics-and-circuits-n3e">electronics</a>. 3D printing opens up a new world to hobbyists and makers, because it lowers down the barriers around creating original prototypes. But 3D printing is not useful just for prototyping; you can use it to fix stuff in your home, to create useful tools and adapters with different materials, to decorate, and to create funny original toys for your children.</p>
<p>The most exciting part of it is that you can download thousands of existing models for free in sites like <a href="https://printables.com">Printables</a>, and you can always create your own unique designs with 3D software and even using code!</p>
<h2>How it Works</h2>
<p>There are different methods of 3D printing out there, but we'll focus on FDM 3D printing because that's the most popular nowadays.</p>
<p>FDM stands for <a href="https://en.wikipedia.org/wiki/Fused_filament_fabrication#Fused_deposition_modeling">Fused Deposition Modeling</a>, which in practice means that a continuous stream of melted material (usually plastic filament) is extruded through a nozzle and is immediately solidified, fusing together with existing layers on the printing plate.</p>
<p>It is a slow process, but the results can be quite impressive. The following timelapse gives a better idea of how it works. This print took about 20 hours to complete on the Prusa MK3S:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/GVxVYZv7oM8?si=XV-p5EKncwm_3Pua" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<h2>Choosing a 3D Printer</h2>
<p>I’m not giving you advice on which printer to buy. Go check some Youtube videos, read about it, consider what you plan on doing with it. There are many vendors out there offering 3D printers at different price ranges, from a couple hundred dollars to a few thousands. That being said, for our first 3D Printer we chose the <a href="https://prusa3d.com">Prusa</a> MK4 kit, and we were very happy with it. More recently, we got the newest MK4 model, and it's been a really nice upgrade.</p>
<h3>Kit or Assembled?</h3>
<p>If you want something that is just "plug and play" (almost, as they usually still require some calibration anyways), you should consider buying a printer that is already assembled. They are more expensive, however you will spare a lot of time and effort into putting everything together – even with the best documentation, for beginners it's still quite hard to assemble everything right.</p>
<p>It is definitely possible thou, so if you want to spare some money and you are not in a hurry (meaning: you will have time and patience to assemble things carefully) you should go for the kit.</p>
<p>For our first printer, we chose the Prusa MK3, and I'm glad we went for the kit. Assembling the kit has taught us so much! The best thing about the kit is that it teaches you <strong>a lot</strong> about the machine. You'll get a better understanding of how it works, mechanically speaking. If something breaks, if something doesn’t seem right, you will be in a much better place to understand what happened, and maybe fix it.</p>
<p>However, when we had the chance to upgrade to the latest model, we decided to get the pre-assembled printer to save time and have the assurance that everything is optimized for the best possible results.</p>
<h2>3D Printing Filament</h2>
<p>In order to print something with a 3D printer, you'll need 3D printing filament. These are typically sold in rolls and measured in weight (1kg rolls, 500g rolls..). There are a lot of different brands and materials, the most popular being PLA.</p>
<p>PLA is the most straightforward material to print. Other materials, such as ABS, can be quite difficult to print, requiring special conditions like a stable room temperature and a very hot print bed.</p>
<p>Another good option that prints easily and offers a much higher resistance than PLA is <em>PETG</em>. PETG is suitable for things that shouldn't break easily and stuff that must endure higher temperatures or just being exposed outdoors.</p>
<p>Other materials include flexible filament, copper-infused (also other metals), carbon fiber, and many more. These are typically harder to print, serving special purposes.</p>
<h2>3D Printing Software</h2>
<p>3D printing requires special software to turn the STL files we download from sites like <a href="http://printables.com">Printables.com</a> into actual GCODE that is understood by your 3D printer. The process of turning an STL into GCODE is called <strong>slicing</strong>. A popular slicing program is <a href="https://slic3r.org/">Slic3r</a>, and there's also the <a href="https://www.prusa3d.com/prusaslicer/">PrusaSlicer</a> for those who own Prusa printers, either original or derivative ones.</p>
<p>To create original models, you can use a 3D modeling software - there are many to choose from. The following timelapse shows me using Freecad to design a simple shapes toy for my girl:</p>
<p><iframe width="560" height="315" src="https://www.youtube.com/embed/pIEu5Qta91w?si=J0_Ial2nLcKWlVx1" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe></p>
<p>Even more exciting is to use <strong>code</strong> to create 3D models. You can do that with <a href="https://www.openscad.org/">OpenScad</a>, an open source platform for creating solid 3D models through code. This enables you to create customizable 3D objects!</p>
<p>Here's a sneak peek of a simple nametag I've created with this tool:</p>
<pre><code>font = "Ubuntu Mono";
letter_size = 60;
padding = 20;
string = "@erikaheidi";
textlen = len(string);
box_width = letter_size*textlen*0.8;
box_height = letter_size + (2*padding);
box_thickness = 20;
start_x = 0 - (box_width / 2) + padding;
start_z = padding;
module text3d(string) {
linear_extrude(height = box_thickness - 10) {
text(string, size = letter_size, font = font, halign = "center", valign = "center", $fn = 64);
}
}
module tag(width, height, thickness) {
spacing = 20;
difference() {
//tag body
linear_extrude(thickness) {
square([width, height], center = true);
}
//tag hole for lanyard
linear_extrude(thickness) {
hole_x = 0 - width / 2 + spacing;
hole_y = 0 - height / 2 + spacing;
translate([hole_x, hole_y, 0]) square([15, height-spacing*2]);
}
}
}
difference() {
tag(box_width, box_height, box_thickness);
translate([0+padding, 0, start_z]) text3d(string);
}
</code></pre>
<p>Did you like what you read? Then check out my <a href="/3D-Printing/20231109_freecad-for-beginners">FreeCAD for Beginners</a> post for a introduction to 3D design for printing with FreeCAD.</p>
Erika HeidiHow to Install and Set Up Terminator + Oh My ZSH! on Ubuntuhttps://eheidi.dev/posts/installing-ohmyzsh-ubuntuhttps://eheidi.dev/posts/installing-ohmyzsh-ubuntuIn this step-by-step guide, learn how to install and set up Terminator and Oh My ZSH! on Ubuntu for a pretty and handy terminal.Tue, 23 May 2023 00:00:00 GMT<p>I've been a fan and loyal user of <a href="https://ohmyz.sh/">Oh-my-Zsh!</a> for many years; it makes my shell more useful with little things such as git branch information and smart autocomplete.</p>
<p>For terminal software, I really enjoy using <a href="https://gnome-terminator.org/">Terminator</a>, because it allows me to spawn several tiled terminals in a single window, with a custom arrangement that can expand and shrink easily.</p>
<p>The combination of Terminator + Oh My ZSH for me is perfect to improve my productivity since it allows me to see more information instantly and organize terminal windows into tiles with a couple clicks.</p>
<p>In this guide, I'll share in detail how I set up my Terminator with Oh My ZSH and the Powerlevel10k theme.</p>
<h2>Step 1: Install Terminator</h2>
<p>To get started, install Terminator with:</p>
<pre><code>sudo apt install terminator
</code></pre>
<p>When the installation is finished, hit the window key and type <code>terminator</code> to open Terminator from the Ubuntu desktop. It will look like this:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/05.png" alt="Terminator before customization" /></p>
<p>Let's configure it so it looks nicer. Right-click on the terminal window and open "Preferences" on the menu. Go to the "Profiles" tab to customize the default profile.
Later on you can create multiple profiles changing terminal font size and colors, so for instance you can have a "screen" profile for when you need to present content in your terminal.</p>
<p>On the "General" tab, <strong>uncheck</strong> "Show titlebar":</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/06.png" alt="Terminator disable title bar" /></p>
<p>Then, go to the "Background" tab and set transparent background with a shade of 0.80:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/07.png" alt="Terminator background color" /></p>
<p>After the change, close the preferences window. Your Terminator should now look similar to this:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/08.png" alt="Terminator with transparent background" /></p>
<p>To create tiled windows, right-click on the terminal window and select "split horizontally" or "split vertically":</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/09.png" alt="Terminator split" /></p>
<p>Each new window can be split again, so you have infinite ways to customize the tiles:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/10.png" alt="Terminator split with 3 tiles" /></p>
<p>For quick access, pin it to your Dock:</p>
<ul>
<li>hover the mouse to the bottom of the screen to open Dock;</li>
<li>right-click the Terminator icon;</li>
<li>select "Pin to Dash" to pin it to the Dock.</li>
</ul>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/11.png" alt="Terminator pin to Dash / Dock" /></p>
<h2>Step 2: Install Oh-My-Zsh!</h2>
<p>First install the dependencies <code>zsh</code> and <code>fonts-powerline</code> to support icons in your terminal:</p>
<pre><code>sudo apt install zsh fonts-powerline
</code></pre>
<p>Now you can run download and execute the Oh-my-Zsh <a href="https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh">installation script</a>.</p>
<pre><code>sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
</code></pre>
<p>The installation will prompt you to confirm that you want to use <code>zsh</code> as default bash. Confirm to continue. When it finishes, you should get a screen similar to this:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/12.png" alt="Oh my Zsh installed" /></p>
<p>You'll need to restart Terminator in order to load the ZSH shell with OMZ.</p>
<h2>Step 3: Customize Oh-my-ZSH!</h2>
<p>OMZ has several themes that you can install to better customize your terminal, showing useful information based on plugins. Some themes may need additional steps to run properly, such as setting special fonts that support icons or installing dependencies.</p>
<p>To choose a theme, you can have a look at OMZ <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes">Themes Section</a> and also the <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes">external themes</a> section from their Wiki to choose a theme that you like.</p>
<p>Here are some nice themes to give a try:</p>
<ul>
<li><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#agnoster">Agnoster</a> - A real nice theme that comes built-in, so you don't need to install any extras.</li>
<li><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/Themes#jonathan">Jonathan</a> - Another built-in theme that adds useful information to the prompt, with a more minimalist look and feel.</li>
<li><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes#agnosterzak">AgnosterZak</a> - Based on Agnoster, this theme packs more info into your prompt such as battery life and date/time.</li>
<li><a href="https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes#powerlevel10k">Powerlevel10k</a> - Useful theme that shows lots of info in the terminal and has different color themes. This is the theme that I am currently using.</li>
</ul>
<p>I personally have been using the Agnoster theme for years, but decided to try something a bit more resourceful and the Powerlevel10k theme offers a lot of extras, and it's super easy to configure with their built-in wizard. This is how my terminal looks like now:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/13.png" alt="Oh my Zsh with Powerlevel10k theme installed" /></p>
<p>For the built-in themes, you just need to edit your <code>.zshrc</code> and change the <code>ZSH_THEME</code> env var to the name of the theme you want to use. Check the wiki page to see if the theme has special configuration options.</p>
<h3>Installing the Powerlevel10k Theme (Optional)</h3>
<p>The theme I chose for my new setup is the <a href="https://github.com/ohmyzsh/ohmyzsh/wiki/External-themes#powerlevel10k">Powerlevel10k Theme</a> - it's an external theme that requires installation and setup via a friendly CLI wizard tool. Follow these instructions if you want to try it out.</p>
<p>First, install their recommended font. Download the following font files:</p>
<ul>
<li><a href="https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Regular.ttf">MesloLGS NF Regular.ttf</a></li>
<li><a href="https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold.ttf">MesloLGS NF Bold.ttf</a></li>
<li><a href="https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Italic.ttf">MesloLGS NF Italic.ttf</a></li>
<li><a href="https://github.com/romkatv/powerlevel10k-media/raw/master/MesloLGS%20NF%20Bold%20Italic.ttf">MesloLGS NF Bold Italic.ttf</a></li>
</ul>
<p>Then, go to your <code>Downloads</code> folder, double-click each font and click on the "Install" button to get the font installed to your system.</p>
<p>With the fonts installed, you'll need to update your Terminator profile to use the new font. Right-click on the Terminator window, then access "Preferences" on the menu, and access the "Profiles" tab. With the <code>default</code> profile selected, <strong>uncheck</strong> the option that says "Use the system fixed width font". Then click on the font select box and choose <strong>MesloLGS NF Regular</strong> font. You may want to increase the font size, while you're at it. Close the window when you're finished and Terminator should now be using the recommended font for Powerlevel10k.</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/terminator-font.png" alt="Changing Terminator font" /></p>
<p>Next, install Powerlevel10k by cloning it into your OMZ themes folder:</p>
<pre><code>git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k
</code></pre>
<p>Finally, edit your <code>~/.zshrc</code> and change your <code>ZSH_THEME</code> to <code>powerlevel10k/powerlevel10k</code>:</p>
<pre><code>#~/.zshrc
ZSH_THEME="powerlevel10k/powerlevel10k"
</code></pre>
<p>After that, close and open again Terminator to load the new theme. The first time you run OMZ with the Powerlevel10k theme, a CLI wizard script will guide you through the prompt configuration. You can choose from a wide variety of options and styles, it's very intuitive.</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/15.png" alt="Setting up the Powerlevel10k theme with p10k script" /></p>
<p>It's worth noting that you can run this configuration wizard again at any time to reconfigure your prompt:</p>
<pre><code>p10k configure
</code></pre>
<p>After you're satisfied with your initial prompt setup, there's a few more settings you can change by editing your <code>~/.p10k.zsh</code> file. This config file has a long list of prompt elements that you can enable and disable, so make sure to check it out and uncomment what you'd like to test.</p>
<p>For instance, I enabled the PHP-related elements, so when I open a git-based PHP project I see the PHP version currently set up within the system:</p>
<p><img src="https://onlinux.erikaheidi.com/ubuntu2304/setup/prompt_elements.png" alt="Prompt elements" /></p>
<p>Don't forget to close and re-open Terminator to source the changes you made to the <code>~/.p10k.zsh</code> file.</p>
<p>I hope you have enjoyed this guide - let me know <a href="https://twitter.com/erikaheidi">on Twitter</a> which Oh My ZSH! theme is your favorite!</p>
<p><em>Update: the fine folks from Oh My ZSH shared a coupon for 10% discount at their <a href="https://t.co/giYPX5C2ss">merch store</a>, if you love the project consider getting some stickers for support ☺️ Here's the code: <strong>10viaERIKA</strong></em></p>
Erika HeidiInformation Architecture and Content Planning for Documentation Websiteshttps://eheidi.dev/posts/information-architecturehttps://eheidi.dev/posts/information-architectureIn this post we'll learn about information architecture in the context of documentation websites and see tips to get your docs organized.Sun, 15 Jan 2023 00:00:00 GMT<p>In a <a href="/tech-writing/20221216_setting-up-a-documentation-site">previous article in this series</a>, we've seen how to set up a dedicated documentation website with Hugo, and how to host it for free on Netlify. Now you may be asking yourself what is the best way to organize your documentation so that users can make the best out of it and are able to find what they need more easily.</p>
<p>Although there is no magic formula to write great docs, some things will be decisive in creating a good experience for the final user. Organization, content type consistency, and good navigation are important features for any documentation.</p>
<p>In this post we'll learn about information architecture in the context of documentation websites and see tips to get your docs organized.</p>
<h2>1. Introduction to Information Architecture</h2>
<p>The term "Information Architecture" (IA) is used in multiple fields of study to refer to the practice of organizing and labeling (or categorizing) content in such a way that supports usability and <em>findability</em>. In the context of user experience, one of the main goals of IA is to reduce the cognitive load necessary for users to find the content they need.</p>
<p>Information Architecture studies will take into consideration three elements that compose the "Information Ecology" of any body of content: <strong>user</strong>, <strong>content</strong>, and <strong>context</strong>. These must be aligned in order to create a good experience for final users, whether it's in a physical library or on a documentation website.</p>
<p>When talking specifically about websites, authors Louis Rosenfeld and Peter Morville identified 4 components for a successful information architecture in their book <a href="https://books.google.nl/books/about/Information_Architecture_for_the_World_W.html?id=hLdcLklZOFAC&redir_esc=y">Information Architecture for the World Wide Web</a>:</p>
<ul>
<li><strong>Organization systems</strong>: refers to the groups or categories in which content is organized. Documentation websites typically use a hierarchical system with broader categories on top, narrowing down to more specific ones as you navigate further down the taxonomy tree.</li>
<li><strong>Labeling systems</strong>: labels help users quickly identify sections and categories of content.</li>
<li><strong>Navigation systems</strong>: help users navigate the content, and can be of different types. A website can combine various styles of navigation to help surface content that otherwise would be difficult to find.</li>
<li><strong>Search systems</strong>: it is important to allow users to search through your content, since navigation alone is not likely to bring all relevant results a user is looking for.</li>
</ul>
<p>Most CMSs and static site generators will have implementations of these systems as built-in features. Your job is to plan your content structure and taxonomy, keeping in mind your project's context and audience.</p>
<h2>2. Content Structure for Static Websites</h2>
<p>Most static site generators that are used for documentation websites (such as Hugo or mkdocs) rely heavily on folder hierarchy to define how content is grouped and exhibited.</p>
<p>If you ever tried to optimize a website for search engines you'll know that changing a URL structure later on will have a negative impact on users experience, unless you make sure to include redirects, which can be difficult to set up. That's why it's so important to plan how your content will be organized, and do it in such a way that allows your documentation to grow, hopefuly without over-engineering it. You don't want an excessively nested structure of folders, but you have to make sure content is organized in a way that makes sense.</p>
<p>Defining categories and content types can be a good starting point to decide how you want to organize your top-level directories. Here are some popular choices, from more broad to more specific:</p>
<ul>
<li>By locale / language, e.g.: <strong>eng_US</strong>, <strong>pt_BR</strong>...</li>
<li>By project version, e.g.: <strong>latest</strong>, <strong>2.2.1</strong>...</li>
<li>By topic, e.g.: <strong>getting-started</strong>, <strong>advanced-usage</strong>...</li>
<li>By category, e.g.: <strong>open-source</strong>, <strong>products</strong>...</li>
<li>By content type, e.g.: <strong>tutorials</strong>, <strong>videos</strong>...</li>
</ul>
<p>Ultimately, the decision of how your top-level directories should look like depends on the size of your project and your own bandwidth for maintenance and updates. If you barely have the time to write basic docs, you shouldn't bother with multiple languages or multiple versions. This is important for large projects, thou - there will be people using legacy versions of your project and you should support them at least with the basic docs that were already there.</p>
<p>For small projects, organizing top-level directories by topic is a good strategy, since it allows you to put together a few different collections without over engineering the docs structure. If your site has content that doesn't fit well together (such as showing product docs and open source tutorials in the same space) you can use categories to help clarify the difference.</p>
<p>I wouldn't recommend using the content type as top-level taxonomy unless your content doesn't have a lot of variety in topics. It works well as a sub-level taxonomy, thou, inside a category or topic.</p>
<h2>3. Content Types</h2>
<p>A content type is a representation of information that follows a similar format, something that users can recognize across your body of content. Having different content types is a good way to provide variety in your content, and also enables you to reuse a similar content in a slightly different format, for a different audience. For instance, you may have a tutorial on a subject, going to each step in much detail. A <em>quickstart</em> version of the tutorial could be more direct to the point, with only the commands you need to run to accomplish the same objective.</p>
<p>Defining content types can also help you speed up your content production because you won't need to think about the doc structure each time, you can reuse the same format of other articles already published.</p>
<h2>4. Content Planning</h2>
<p>Some of the decisions around content structure and taxonomy will only make sense when you have enough docs. You don't need to write them all at once before publishing your documentation website, but you can plan ahead and define your priorities.</p>
<p>Think about enough docs to make most users successful when trying your project. There will always be edge cases and scenarios that you can't predict or even reproduce on your own, so keep that in mind when defining your priorities. Documentation is never finished, there will always be things to include, update, or to improve.</p>
<p>Some topics or sections I consider essentials:</p>
<ul>
<li><strong>Getting Started</strong>: A section showing in details how to get the project installed and test that it works.</li>
<li><strong>Usage</strong>: A section exploring a more detailed view of the project's usage and main commands.</li>
<li><strong>Advanced</strong>: A section with some advanced usage options and use cases.</li>
</ul>
<p>Consider also having one or more step-by-step tutorials that show a practical scenario using your project, and a "troubleshooting" section or page.</p>
<h2>Practice Session</h2>
<p>Now that we've seen some theory and tips to get you started with the information architecture of your documentation website, here are a few questions to help you practice:</p>
<p><strong>A)</strong> Who is the audience of your project? What level of experience do you expect users to have in order to use your project?</p>
<p><strong>B)</strong> What is the context around your project? Think about why you built it, how large is the surrounding community, if there are "competitors" or similar projects already established and how you position yourself in that market.</p>
<p><strong>C)</strong> Consider the context of your project and your audience. What kind of content do they need? Are regular documentation / reference pages enough, or do you need to fill some gaps with conceptual content explaining elements from your ecosystem? Should you link out to other resources or create them yourself?</p>
<p><strong>D</strong>) Which content types will serve your users better? Can you reuse content for increase output? What kind of media resources can you provide to enrich the user's experience? Think about graphs, diagrams, demo videos, slides...</p>
<p><strong>E</strong>) What content must absolutely be there? Make a list (or spreadsheet, if you want to get organized) with tentative titles of all content you would like to have there. Then, organize them by priority and come down to 5 doc pages that should be your starting point.</p>
<h2>Conclusion</h2>
<p>Information Architecture is a field of study that can help designers and content creators make decisions around how they organize and categorize content, in such a way to improve the user's experience. In the context of static sites, the content structure relies heavily on directory hierarchy, so it's important to plan in advance what kind of topics, categories, and content types you want to feature.</p>
Erika HeidiSetting up a Documentation Website for your Software Project with Hugo and Netlifyhttps://eheidi.dev/posts/setting-up-a-documentation-sitehttps://eheidi.dev/posts/setting-up-a-documentation-siteIn the second part of our series, we'll see how to set up a dedicated documentation website for your software project using the Hugo static site generator, and having it hosted for free on Netlify.Tue, 10 Jan 2023 00:00:00 GMT<h2>Introduction</h2>
<p>In a previous post of this series, we've seen <a href="/tech-writing/20221212_documentation-101">tips and best practices to create a good readme</a> for your software project, and how to organize an initial set of markdown docs to cover the basics.</p>
<p>Having some basic docs alongside your code works well as a starting point, but depending on the size of your project and the amount of features and configuration involved to set it up, having a dedicated documentation website is a better long-term solution to keep docs organized, making things easier to find and to link out.</p>
<p>In this post, which is part 2 on my Documentation 101 series, we'll see how to set up a dedicated documentation website for your software project using the Hugo static site generator, and having it hosted for free on Netlify.</p>
<h2>Choosing a platform</h2>
<p>There are quite a few different solutions nowadays to build and to host your documentation site for free.</p>
<p>A few combinations that I have personally tried before:</p>
<ul>
<li>GitHub Pages: typically built in a separate branch of the project, can become confusing with time. Less freedom to customize.</li>
<li>Readthedocs + mkdocs: this is a good combination using the free documentation platform <a href="https://readthedocs.org">Readthedocs</a>. You get a free .readthedocs subdomain, and can also set up a custom domain. I use it for the <a href="https://docs.minicli.dev/en/latest/">Minicli</a> docs, overall a good solution but I find it to be a bit flaky sometimes, specially when there are updates.</li>
<li>Netlify + Hugo: my favorite so far, because this enables the "preview on PR" feature that gives you a preview whenever a PR is open (comes as a comment from the Netlify bot). The downside is that you'll want to use a custom domain (could be a subdomain you already own, or a dedicated domain name for that project) otherwise your site will have a really weird address.</li>
</ul>
<p>Other reasons why I liked using Hugo include the fact that it can be widely customized and also that it's easy to host.</p>
<h2>Installing Hugo</h2>
<p><a href="https://gohugo.io/">Hugo</a> is a popular static site generator written in Go. It uses markdown documents to generate the content, which is ideal to keep your documentation decoupled from styling and formatting. Metadata is added through a front matter section, very similar to what we use at DEV.to for writing posts using the basic markdown editor.</p>
<p>Hugo sites can be hosted for free on Netlify and several other platforms.</p>
<h3>1. Downloading and Installing</h3>
<p>First, download and install the latest version of Hugo available for your system. You can find the appropriate package on their <a href="https://github.com/gohugoio/hugo/releases">Releases</a> page on GitHub. You should avoid using your system package manager in order to make sure you get an updated version of Hugo.</p>
<p>For Ubuntu users, for instance, download the <code>.deb</code> file and install it with <code>dpkg</code>:</p>
<pre><code>sudo dpkg -i ~/Downloads/hugo_0.107.0_linux-amd64.deb
</code></pre>
<p>Once you're finished, run the <code>hugo version</code> command to make sure Hugo is available system-wide:</p>
<pre><code>hugo version
</code></pre>
<p>You should get output similar to this:</p>
<pre><code>hugo v0.107.0-2221b5b30a285d01220a26a82305906ad3291880 linux/amd64 BuildDate=2022-11-24T13:59:45Z VendorInfo=gohugoio
</code></pre>
<h3>2. Creating a new Hugo Project</h3>
<p>Now you can create a new Hugo site with the following command. For the examples in this guide, I'll use "mydocs" as site name.</p>
<pre><code>hugo new site mydocs
</code></pre>
<p>You should get output similar to this:</p>
<pre><code>Congratulations! Your new Hugo site is created in /home/erika/Projects/mydocs.
Just a few more steps and you're ready to go:
1. Download a theme into the same-named folder.
Choose a theme from https://themes.gohugo.io/ or
create your own with the "hugo new theme <THEMENAME>" command.
2. Perhaps you want to add some content. You can add single files
with "hugo new <SECTIONNAME>/<FILENAME>.<FORMAT>".
3. Start the built-in live server via "hugo server".
Visit https://gohugo.io/ for quickstart guide and full documentation.
</code></pre>
<p>With the basic installation in place, you can start customizing your site.</p>
<h3>3. Installing a Theme</h3>
<p>The <a href="https://themes.gohugo.io/">official Hugo website</a> has a large collection of themes ready to use. You can nail down your search by selecting the "docs" category to find a theme that is more targeted at documentation, these usually include extensions to improve code highlighting and navigation that facilitates indexing documentation.</p>
<p>For this tutorial, we'll use the <a href="https://themes.gohugo.io/themes/hugo-geekdoc/">Geekdoc</a> theme, the same I have set up for the <a href="https://yamldocs.dev/">yamldocs</a> documentation.</p>
<p>Generally speaking, you should follow the installation instructions provided by the theme you choose. Some themes are npm-based and require that in order to be properly installed locally.</p>
<p>For the Geekdocs theme, you just need to download and unpack the theme into the <code>themes</code> folder of your site. You can do that with the following commands:</p>
<pre><code>cd mydocs/
mkdir -p themes/hugo-geekdoc/
curl -L https://github.com/thegeeklab/hugo-geekdoc/releases/latest/download/hugo-geekdoc.tar.gz | tar -xz -C themes/hugo-geekdoc/ --strip-components=1
</code></pre>
<p>Next, you'll need to edit your <code>config.toml</code> file, which currently looks very minimal. We'll add options that are specific to the theme and should set up some nice extensions.</p>
<p>This is how my <code>config.toml</code> file looks like after updating:</p>
<pre><code>baseURL = "http://localhost"
title = "My Documentation Site"
theme = "hugo-geekdoc"
pluralizeListTitles = false
# Geekdoc required configuration
pygmentsUseClasses = true
pygmentsCodeFences = true
disablePathToLower = true
# Required if you want to render robots.txt template
enableRobotsTXT = true
# Needed for mermaid shortcodes
[markup]
[markup.goldmark.renderer]
# Needed for mermaid shortcode
unsafe = true
[markup.tableOfContents]
startLevel = 1
endLevel = 9
[taxonomies]
tag = "tags"
</code></pre>
<p>Once you're finished editing, don't forget to save the file.</p>
<p>Next, run the development server to check your site:</p>
<pre><code>hugo server -D
</code></pre>
<p>You should see a page like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o5pren4q09oaqkvi37sy.png" alt="Hugo website default" /></p>
<p>Naturally, it looks a bit empty, since there aren't any documents yet. Let's first have a look at the files structure so that you know where everything is:</p>
<pre><code>.
├── archetypes
│ └── default.md
├── assets
├── content
├── data
├── layouts
├── public
│ ├── categories
│ ├── tags
│ ├── index.xml
│ └── sitemap.xml
├── resources
│ └── _gen
├── static
├── themes
│ └── hugo-geekdoc
└── config.toml
</code></pre>
<p>Here are a few important directories you should know about:</p>
<ul>
<li><strong>archetypes</strong>: this directory contains templates for the markdown files that are generated through the "hugo new" command. You can set up different archetypes for different content types, setting default tags and other metadata for instance.</li>
<li><strong>content</strong>: the markdown files with your documentation will live here.</li>
<li><strong>layouts</strong>: here you will find the HTML files that are the base for your site. This folder is empty by default, but you can check the <code>themes/hugo-geekdoc/layouts</code> folder and you'll find out the layouts currently being used in your site. You'll notice that the theme replicates the folder structure of the root folder, and that is important to allow you to overwrite any templates that are defined by your theme. To do that, you just need to create a layout file with the same name in the root <code>layouts</code> folder, and these will take higher precedence than the layouts defined by the theme.</li>
<li><strong>static</strong>: any static resources such as logos and other images used by the site should be placed here.</li>
<li><strong>public</strong>: this is where the static HTML files are located when you build your website, so this is the directory that should be set as your document root when hosting Hugo.</li>
</ul>
<p>Check the <a href="https://gohugo.io/getting-started/directory-structure/">official docs</a> to learn more about Hugo's directory structure.</p>
<h3>4. Building your Docs</h3>
<p>Now that the site is up and running, you can start creating your documentation pages. This is where the actual work gets done, so take your time! You can always start with a basic "getting started" page and improve your docs later. We'll talk about content planning and organization in the next part of this series.</p>
<p>To create a new piece of content, you can use the "hugo new" command. This command will infer the type of content you're creating based on the path provided as output.</p>
<pre><code>hugo new docs/getting-started.md
</code></pre>
<p>You'll see output similar to this:</p>
<pre><code>Content "/home/erika/Projects/mydocs/content/docs/getting-started.md" created
</code></pre>
<p>Open the file and add some content. Then reload the page on your browser and you should see something like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/528xhsnvmpd5pjru12yp.png" alt="Hugo website with initial getting started page" /></p>
<p>You'll notice that the generated markdown has a boilerplate content. This is based on the <code>themes/hugo-geekdoc/archetypes/docs.md</code> archetype, defined by the theme. You can overwrite this boilerplate content by creating a file with the same name in your <code>archetypes</code> folder.</p>
<p>To learn more about archetypes, check the <a href="https://gohugo.io/content-management/archetypes/">official Hugo docs</a>.</p>
<h2>Publishing your Hugo site to Netlify</h2>
<p>As mentioned before, there are multiple ways in which you can host your Hugo website for free. The biggest advantage of using Netlify in my opinion is the ability to use their build preview feature, which creates a temporary deployment with a random URL where you can preview any changes brought in a pull request on GitHub.</p>
<p>We'll now see how to get this set up.</p>
<h3>1. Create an account on Netlify</h3>
<p>Start out by creating a (free) account on <a href="https://netlify.com">Netlify</a>. You can sign up with your GitHub account to facilitate bringing in your repository if it's hosted there. You should be able to get a "starter" account, which should be enough to get your static site hosted for free.</p>
<p>Once you're all set up, you'll land in a dashboard similar to this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wuzo4gol99h5sqoidwei.png" alt="Netlify Dashboard" /></p>
<h3>2. Import your project</h3>
<p>Click on the "Add new Site" button and you'll get a dropdown. Choose the first option "Import an existing project" and follow the instructions to import your project from your code hosting platform such as GitHub.</p>
<p>You may need to authorize Netlify to have access to your repositories. Then, you'll be able to choose which repository you want to import. Select your Hugo repository and advance to the next page.</p>
<h3>3. Configure deployment settings for Hugo</h3>
<p>In this page you'll find the deploy settings. Luckily for us, Netlify is able to detect that it's a Hugo website and already sets up some default values for us. Because the theme we chose is simple and doesn't require npm or anything like that, those default values are more than enough to get us up and running. This is what you should see:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bou34ef2d8zqyoivk24p.png" alt="Netlify default deploy settings for Hugo" /></p>
<p>Click on "Deploy Site" to finish the setup process.</p>
<h3>4. Preview Project</h3>
<p>Once you're back to the dashboard, you'll see that your new site is being built, and has a random subdomain. You'll be able to set up a custom domain later on.</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uanur1elhe9c9lp8kl4e.png" alt="Netlify Deploy" /></p>
<p>You can now access the temporary URL to preview your site and make sure it looks the same as you have locally.</p>
<h3>5. Configure Deploy Preview</h3>
<p>The deploy preview feature should be automatically enabled for you, but you'll need to <a href="https://docs.netlify.com/configure-builds/repo-permissions-linking/#authentication-with-the-netlify-github-app">authorize the Netlify app</a> within your project repository in order to allow the Netlify bot to post a comment in your PRs with the link to the deploy preview.</p>
<p>To check if this feature is enabled, go to "Deploys" and then "Continuous Deployment" on the left menu. You should see a section like this:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r00hjmfos4dtsfo6nvb1.png" alt="Deploy previews default settings on Netlify" /></p>
<p>Check the <a href="https://docs.netlify.com/site-deploys/deploy-previews/">Netlify docs on deploy previews</a> for a more detailed guide on how to set this up.</p>
<h3>6. Configure custom domain name (optional)</h3>
<p>The final step of this process is setting up a custom domain name for your website. Although optional, this is highly recommended, otherwise you'll have a random domain name that doesn't relate in any way to your project name. Once you set that up, you'll also be able to secure your site with a Let's Encrypt certificate (Netlify does that for you automatically).</p>
<p>To set up a custom domain, go to the "Set up a custom domain" link that shows up as step number 2 in the "Set up your website" section of the dashboard. You can use an existing domain you own or you can register a new domain through Netlify. Follow the instructions there and be aware it can take a few hours for your site to be reachable via the custom domain.</p>
<p>Check the <a href="https://docs.netlify.com/domains-https/custom-domains/">official Netlify docs</a> for more guidance on how to set up a custom domain for your site.</p>
<h2>Conclusion</h2>
<p>Although having docs living alongside your codebase can be a valid solution in many cases, you may want to set up a dedicated documentation website if your project starts to get more adoption or simply if you want to improve users experience with a long-term home for your project docs. There are a few different ways in which you can build and host documentation websites; in this article, we've seen how to set up a documentation website with Hugo and have it hosted for free on Netlify.</p>
<p>In the next part of this series, we'll talk about content planning and organization, with best practices to keep your documentation clean and easy to follow.</p>
Erika HeidiDocumentation 101: creating a good README for your software projecthttps://eheidi.dev/posts/documentation-101https://eheidi.dev/posts/documentation-101In this article, which is part 1 of a series on how to write good documentation, we'll see some tips to write a good README file for your project.Sun, 01 Jan 2023 00:00:00 GMT<p>Having a good documentation for your open source project is an important (and often overlooked) feature to drive adoption and show the full potential of what users can accomplish with your application or library.</p>
<p>Unfortunately, documentation often grows in a much slower rate than code, mainly because some implementations that look rather simple may spawn a huge amount of possible use cases and variations for how something is done within an app or lib. It is never possible to cover all possible scenarios, that's why the first job of a technical writer is to scope and prioritize. It's very important to focus on what's essential knowledge and must be documented first to support the most common use cases.</p>
<p>In this article, which is <strong>part 1</strong> of a series about <strong>Software Documentation for Beginners</strong>, I'll share some tips to build a good README file for your project.</p>
<h2>The README file</h2>
<p>The project's README file is often the first contact users will have with your project, since it's what they'll see first when directed at your project's repository. That's why it's important to prioritize having a good README as a starting point for your project's documentation.</p>
<p>This is a TL;DR of what we'll cover today:</p>
<ul>
<li>
<ol>
<li>README size (Less is More)</li>
</ol>
</li>
<li>
<ol>
<li>Splitting README into additional docs</li>
</ol>
</li>
<li>
<ol>
<li>Essential Information</li>
</ol>
</li>
<li>
<ol>
<li>Using Badges</li>
</ol>
</li>
</ul>
<p>Naturally, different projects have different things to showcase in a README, but these tips should work as a good starting point for most software projects.</p>
<h2>1. Less is More</h2>
<p>You may be tempted to put everything in your README, like how to install and use the project, how to deploy, how to debug... But the README should be seen more like an entry point, where you share the most important information and links for more complete docs covering these topics in more detail.</p>
<p>Naturally, when you are starting out, having just a README is fine. But a very long README is not attractive, makes it harder to find information since there isn't a table of contents or menu to navigate, which ultimately goes against a good user experience. Shorter READMEs that link out to relevant resources make a project look more organized and less complicated.</p>
<p>What if I don't want to create a dedicated documentation website for this project? Well, in this case you may consider creating a <code>docs</code> folder in the root of your project, where you can keep additional markdown documentation that can be browsed directly from your code hosting platform (assuming GitHub).</p>
<h2>2. Splitting README into additional docs</h2>
<p>For in-repo docs, you can create a <code>/docs</code> directory in the root of your application, and use a <code>/docs/README.md</code> file as entry point or index for your docs.</p>
<p>Content ideas for this folder:</p>
<ul>
<li>installation.md - A doc showing in details how to get the project installed.</li>
<li>usage.md - A more detailed view of the project's usage and main commands.</li>
<li>advanced.md - A document with some advanced usage options and use cases.</li>
</ul>
<p>These are just some ideas that can work as a starting point. If you feel that you need to create a more complex structure with subfolders, you should seriously consider creating a dedicated documentation website for your project (which we'll cover in upcoming articles of this series).</p>
<h2>3. README Essentials</h2>
<p>Here are a few things you should definitely have in your README:</p>
<ul>
<li>a high-level overview of the project, including the language in which it's written, what it does, why it's useful;</li>
<li>the project requirements;</li>
<li>links to installation docs;</li>
<li>usage overview that gives users a brief idea of how to execute it;</li>
<li>troubleshooting or debug tips (can be a link to a separate doc);</li>
<li>links to other resources to learn more.</li>
</ul>
<p>Ideally, these should be short instructions that link to more comprehensive docs whenever necessary.</p>
<p>Other content you should consider to have there, depending on your project's size and goals:</p>
<ul>
<li>a link to a CONTRIBUTING.md document that contains details about how users can contribute to your project, in case it's open source</li>
<li>a link to a CODE_OF_CONDUCT.md document that contains the project's code of conduct.</li>
</ul>
<p>If your project is hosted on GitHub, these will be shown prominently in your project's page on the right sidebar, right below the "about" section.</p>
<h3>Example Structure</h3>
<p>Here is a general structure in markdown that you can use as base for building your project's README:</p>
<pre><code># Project Name
A paragraph containing a high-level description of the project, main features and remarks.
## Requirements
Here you should give a general idea of what a user will need in order to use your library or application. List requirements and then link to another resource with detailed installation or setup instructions.
- Requirement one
- Another requirement
Check the [installation notes]() for more details on how to install the project.
## Usage
Include here a few examples of commands you can run and what they do. Finally link out to a resource to learn more (next paragraph).
For more details, check the [getting started guide]().
## Useful Resources
Include here any other links that are relevant for the project, such as more docs, tutorials, and demos.
</code></pre>
<h2>4. Using Badges</h2>
<p>You can use badges to enrich your README with quick information that is automatically pulled from the project, such as the status of the latest build, the latest stable release version, project license, among others.</p>
<p>There are different services that offer badges for open source projects. As pointed by @mohsin in the comments section of this post, you can pull badges directly from GitHub Actions by going to your workflow page, clicking on the three dots that show up on the top right, and selecting "Create status badge" from the menu:</p>
<p><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bpb6g6xofhwm8vctwcem.png" alt="Screenshot showing where to find the menu to create a status badge from github actions" /></p>
<p>This will show you a dialog with markdown code that you can copy and paste to your README file.</p>
<p>Another good option is to use the site <a href="https://shields.io/">Shields.io</a>, which offers several different badges that you can use for free in your open source project.</p>
<p>For instance, this is the image URL to show the latest release of <a href="https://github.com/erikaheidi/yamldocs">yamldocs</a>:</p>
<pre><code>https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge
</code></pre>
<p>This generates the following badge, which shows the latest release version:</p>
<p><img src="https://img.shields.io/github/v/release/erikaheidi/yamldocs?sort=semver&style=for-the-badge" alt="latest stable release of yamldocs" /></p>
<p>Here's an example of README with multiple badges:
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5frlxoex4fyke8ra1avf.png" alt="Shows badges from yamldocs project readme" /></p>
<h2>Conclusion</h2>
<p>Documentation is an essential part of any software project, and should be taken seriously from the very beginning. The best way to start is by creating a good README that shows the essential information to your users without overwhelming them with content that they may not need in order to get started using your project.</p>
<p>In the next article of this series, we'll talk about other types of documentation, and where you can host your docs when you decide it's time to have a dedicated documentation website.</p>
Erika Heidi