<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://ryand.io/blog/feed.xml" rel="self" type="application/atom+xml" /><link href="https://ryand.io/blog/" rel="alternate" type="text/html" /><updated>2026-07-08T00:53:40+00:00</updated><id>https://ryand.io/blog/feed.xml</id><title type="html">make something</title><subtitle>ryan&apos;s blog about makin things</subtitle><entry><title type="html">music stand</title><link href="https://ryand.io/blog/2026/03/28/music-stand.html" rel="alternate" type="text/html" title="music stand" /><published>2026-03-28T00:00:00+00:00</published><updated>2026-03-28T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/03/28/music-stand</id><content type="html" xml:base="https://ryand.io/blog/2026/03/28/music-stand.html"><![CDATA[<p>Repurposed an old instrument as a decoration.</p>

<h2 id="the-design">the design</h2>

<p>I found my old clarinet from middle school and tried to play it for the first time in 20 years. It didn’t sound very good - must be something wrong with the instrument… Anyways, I figured it would make a nice decoration.</p>

<p><em>Disclaimer - you’re not supposed to leave instruments like this with cork joints constantly assembled - the cork will dry out. Don’t do this with an instrument that you ever intend to play again.</em></p>

<p>I made a simple modular stand that would hold a 29mm OD clarinet, but have some flexibility to accommodate slightly larger ones as well.</p>

<p><img src="./img/pieces.jpg" alt="" /></p>

<p>The arms that hold the instrument were printed on their sides, then press fit into the bottom pieces, using some mickey-mouse-ear style cutouts to make a snug fit.</p>

<p><img src="./img/assembled.jpg" alt="" /></p>

<p>Final assembly:</p>

<p><img src="./img/final.jpg" alt="" /></p>

<p><a href="https://makerworld.com/en/models/2616709-clarinet-holder-display-stand">Model available on maker-world</a></p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="mechanical-engineering" /><category term="decorating" /><summary type="html"><![CDATA[Repurposed an old instrument as a decoration.]]></summary></entry><entry><title type="html">jetson fan cover</title><link href="https://ryand.io/blog/2026/02/18/jetson-fan-cover.html" rel="alternate" type="text/html" title="jetson fan cover" /><published>2026-02-18T00:00:00+00:00</published><updated>2026-02-18T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/02/18/jetson-fan-cover</id><content type="html" xml:base="https://ryand.io/blog/2026/02/18/jetson-fan-cover.html"><![CDATA[<p>I was working on a project with an Nvidia Jetson Orin Nano, and I kept sticking my finger in the cooling fan by accident, so I decided to see how quickly I could design and print something to fix it…</p>

<!-- cspell:ignore jetson -->

<h2 id="the-problem">the problem</h2>

<p>The Nvidia Jetson development board has a large, unprotected cooling fan on the top, and it’s also the easiest part to grab. So whenever I need to move it I tend to accidentally put my finger on the running fan and I’m worried I’m going to break it.</p>

<h2 id="the-design">the design</h2>

<p>I made a really quick line drawing of a box with rounded corners, so it could press fit nicely on top of the fan. I used some minimal cross beams to protect it without impeding airflow too much, and some small bumps to act as standoffs.</p>

<p><img src="./img/printed.jpg" alt="" /></p>

<p>With this rounded-corner press-fit method it fit perfectly on the first try.</p>

<p><img src="./img/mounted.jpg" alt="" /></p>

<p><a href="https://makerworld.com/en/models/2417128-nvidia-jetson-orin-nano-fan-cover#profileId-2650651">Model available on MakerWorld.</a></p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="embedded" /><category term="mechanical-engineering" /><summary type="html"><![CDATA[I was working on a project with an Nvidia Jetson Orin Nano, and I kept sticking my finger in the cooling fan by accident, so I decided to see how quickly I could design and print something to fix it…]]></summary></entry><entry><title type="html">printing desserts</title><link href="https://ryand.io/blog/2026/02/14/printing-desserts.html" rel="alternate" type="text/html" title="printing desserts" /><published>2026-02-14T00:00:00+00:00</published><updated>2026-02-14T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/02/14/printing-desserts</id><content type="html" xml:base="https://ryand.io/blog/2026/02/14/printing-desserts.html"><![CDATA[<p>I needed a heart-shaped mold for a valentine’s day dessert, and wanted to make something shelf-stable because we were traveling.</p>

<h2 id="the-mold">the mold</h2>

<p>I drew up a really quick heart-shape in cad - a square and two semi-circles - and did a thin-extrude to make a hollow shape. I tweaked the dimensions to get around 500K mm^3, which is 2 cups. then I started printing it while melting the butter.</p>

<p>I lined the mold with plastic wrap when I was filling in the popcorn, then I just pushed the whole thing through and wrapped it up.</p>

<h2 id="the-recipe---marshmallow-popcorn-balls">the recipe - marshmallow popcorn balls</h2>

<h3 id="ingredients">ingredients</h3>

<ul>
  <li>1/4 cup butter</li>
  <li>12 oz bag marshmallows</li>
  <li>~10 oz bag pre-popped salted popcorn (use pre-popped and you don’t have to worry about un-popped kernels)</li>
  <li>optional m&amp;ms, chocolate, etc</li>
</ul>

<h3 id="steps">steps</h3>

<ul>
  <li>melt the butter in a pot on low heat</li>
  <li>slowly stir in the marshmallows until melted</li>
  <li>slowly stir in popcorn until evenly coated</li>
  <li>let cool slightly before adding chocolate, etc… or just add this as you’re adding the popcorn to the mold, so it doesn’t get all melted and mashed up</li>
  <li>then gently scoop and press the mixture into your desired mold</li>
</ul>

<p><img src="./popcorn-hearts.jpg" alt="" /></p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="baking" /><category term="recipe" /><summary type="html"><![CDATA[I needed a heart-shaped mold for a valentine’s day dessert, and wanted to make something shelf-stable because we were traveling.]]></summary></entry><entry><title type="html">my very own support system</title><link href="https://ryand.io/blog/2026/01/27/my-very-own-support-system.html" rel="alternate" type="text/html" title="my very own support system" /><published>2026-01-27T00:00:00+00:00</published><updated>2026-01-27T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/01/27/my-very-own-support-system</id><content type="html" xml:base="https://ryand.io/blog/2026/01/27/my-very-own-support-system.html"><![CDATA[<p>The auto-generated supports from my slicer are sometimes messy and overkill. I decided to try my hand at manually creating my own.</p>

<p>An added benefit to this approach is that everything is included with the model, and you don’t have to rely on others to set their slicer settings the same. This can make for more reliable prints when you share a file.</p>

<p>For this project, I wanted to make a little basket to hold this small terrarium, so I could string it up and hang it from the ceiling somewhere.</p>

<h2 id="modeling-and-supports">modeling and supports</h2>

<p>First I modelled the actual thing. I took a picture of the planter straight on and imported that, oriented and scaled it, and traced around it.</p>

<p><img src="./img/cad.png" alt="" /></p>

<p>Then I modelled the supports; just some tiny shapes around the steeper part of the curve, with a minimal contact to the main body.</p>

<p><img src="./img/cad-w-supports.png" alt="" /></p>

<h2 id="printing">printing</h2>

<p>I loaded it into the slicer and stepped through the layers to make sure the supports are actually touching the piece. I ended up having to thicken the top surface slightly.</p>

<p><img src="./img/slicer.png" alt="" /></p>

<p>It printed perfectly, and the supports popped right off easily.</p>

<p><img src="./img/printed.jpg" alt="" /></p>

<p>Finally, I wanted to make sure it would actually safely support the weight. I could try to do some complex calculations using material strength and finite-element-analysis… but I just got a cheap luggage scale instead. I weighed the thing it self - just over a pound. And then I pulled on it to an arbitrarily large amount until I got a satisfying reading - over 8 pounds. This gives me a safety factor of about 6, so I’m very satisfied with that.</p>

<p><img src="./img/weight-test.jpg" alt="" /></p>

<p>Now I just have to figure out where I actually want to hang it…</p>

<p><img src="./img/hanging.jpg" alt="" /></p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="mechanical-engineering" /><category term="supports" /><summary type="html"><![CDATA[The auto-generated supports from my slicer are sometimes messy and overkill. I decided to try my hand at manually creating my own.]]></summary></entry><entry><title type="html">wall hacks</title><link href="https://ryand.io/blog/2026/01/17/wall-hacks.html" rel="alternate" type="text/html" title="wall hacks" /><published>2026-01-17T00:00:00+00:00</published><updated>2026-01-17T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/01/17/wall-hacks</id><content type="html" xml:base="https://ryand.io/blog/2026/01/17/wall-hacks.html"><![CDATA[<p>Someone yanked an outlet out of my wall, so I decided to reinforce it before reinstalling.</p>

<h2 id="the-problem">the problem</h2>

<p>When someone unplugged a cable from my wall, it yanked out the entire electrical box. This was what’s called an “old-work” electrical box. Typically new-work boxes are installed in new construction, attached directly to studs, before the drywall is in place. If you want to add an outlet after the fact, you have make a hole through the drywall and use an old-work box, which has extra front screws with wings that pop out to clamp it in place.</p>

<p><img src="./img/old-work.jpg" alt="" /></p>

<p>The frustrating thing about drywall is that it’s just about as strong as a graham-cracker, and it crumbles whenever you touch it… Luckily the edges of this hole weren’t too severely damaged, but still compromised.</p>

<p><img src="./img/hole.jpg" alt="" /></p>

<h2 id="the-solution">the solution</h2>

<p>I wanted to put a little something between the outlet box wings and the inside of the drywall to distribute the force of the clamps and make it stay in place better. Thankfully I had some 1/8” wood leftover from some laser-cutting projects, so I just hacked off a couple long thin strips.</p>

<p><img src="./img/wood.jpg" alt="" /></p>

<p>I put glue on them, fed them through the hole (careful not to drop them inside the wall) and just kind of slopped them against the inner face of the drywall, along the bottom and top edges of the hole, where the wings will go. I didn’t have clamps small enough so I just used binder clips to keep them in place until the glue dried.</p>

<p><img src="./img/clips.jpg" alt="" /></p>

<p>Next day, I pulled out the clips and put in the new box, good as new!</p>

<p><img src="./img/finished.jpg" alt="" /></p>]]></content><author><name></name></author><category term="diy" /><category term="home-improvement" /><category term="electronics" /><summary type="html"><![CDATA[Someone yanked an outlet out of my wall, so I decided to reinforce it before reinstalling.]]></summary></entry><entry><title type="html">phantom light-switches</title><link href="https://ryand.io/blog/2026/01/07/phantom-light-switches.html" rel="alternate" type="text/html" title="phantom light-switches" /><published>2026-01-07T00:00:00+00:00</published><updated>2026-01-07T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/01/07/phantom-light-switches</id><content type="html" xml:base="https://ryand.io/blog/2026/01/07/phantom-light-switches.html"><![CDATA[<p>I’ve been depopulating some light-switches that don’t do anything, and I needed something to fill the holes, so I came up with a universal design.</p>

<h2 id="the-design">the design</h2>

<p>I made a complicated-looking model really easily using lots of lines and thin-extrudes.</p>

<p>It’s a flat panel with a filler for the light-switch hole and standard spacing for the screws. The outer ones are thru-holes, and the inner ones are smaller so they catch the screw threads, so the plate is held in place.</p>

<p>To make it adjustable and account for the depth of the electrical box, I added a set of detachable washers which you can just fold over and stack behind the plate. You can either fold or tuck them inside the box if unused, or just snap them off.</p>

<p>To make it more 3D-printer friendly, I added some small slots on the bottom to decrease warping, and a rounded edge to make it easier to pop off the bed.</p>

<p><img src="./img/wireframe.png" alt="" /></p>

<p>I used a printer profile with thicker layers to make it print faster, since only a small portion of the top face is visible and it doesn’t require extra strength.</p>

<p>Printed in less than 10 minutes:</p>

<p><img src="./img/printed.jpg" alt="" /></p>

<p>Mounting inside the box - I used two on the top and 3 on the bottom:</p>

<p><img src="./img/uncovered.jpg" alt="" /></p>

<p>Covered up:</p>

<p><img src="./img/complete.jpg" alt="" /></p>

<p>Model available on <a href="https://makerworld.com/en/models/2215312-light-switch-blank-filler-with-optional-standoffs#profileId-2408534">MakerWorld</a>.</p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="home-improvement" /><category term="mechanical-engineering" /><summary type="html"><![CDATA[I’ve been depopulating some light-switches that don’t do anything, and I needed something to fill the holes, so I came up with a universal design.]]></summary></entry><entry><title type="html">modular key hooks</title><link href="https://ryand.io/blog/2026/01/05/modular-key-hooks.html" rel="alternate" type="text/html" title="modular key hooks" /><published>2026-01-05T00:00:00+00:00</published><updated>2026-01-05T00:00:00+00:00</updated><id>https://ryand.io/blog/2026/01/05/modular-key-hooks</id><content type="html" xml:base="https://ryand.io/blog/2026/01/05/modular-key-hooks.html"><![CDATA[<p>A first draft of a modular design for a wall-mounted key-hook that attaches to a light-switch plate.</p>

<h2 id="the-design">the design</h2>

<p><img src="./img/3d-keyhook.png" alt="" /></p>

<p>Attaching to a light-switch plate makes it easer to mount without needing any permanent modifications to the wall. And light-switches are usually next to the door and the last thing you reach for on your way out.</p>

<p>I wanted to be able to print without supports, so I avoided overhangs by splitting the design into multiple pieces. This also helped me iterate because I could replace and reattach a new bottom part without having to completely unscrew and remount the connectors. The connectors have a slot to make them slightly flexible for a good press-fit.</p>

<p>Having the hooks hang low below the wall plate, and flush against the wall helps minimize how far they stick out, so they don’t get in the way when reaching for the light-switch.</p>

<p>The U-shaped curve helps the keys hang slightly away from the wall, so they’re easier to grab.</p>

<p>The final model is available on <a href="https://makerworld.com/en/models/2208638-light-switch-key-hooks#profileId-2400730">MakerWorld</a>.</p>

<p><img src="./img/complete.jpg" alt="" /></p>]]></content><author><name></name></author><category term="cad" /><category term="3d-printing" /><category term="home-improvement" /><category term="mechanical-engineering" /><summary type="html"><![CDATA[A first draft of a modular design for a wall-mounted key-hook that attaches to a light-switch plate.]]></summary></entry><entry><title type="html">custom waterboarding</title><link href="https://ryand.io/blog/2025/12/29/custom-waterboarding.html" rel="alternate" type="text/html" title="custom waterboarding" /><published>2025-12-29T00:00:00+00:00</published><updated>2025-12-29T00:00:00+00:00</updated><id>https://ryand.io/blog/2025/12/29/custom-waterboarding</id><content type="html" xml:base="https://ryand.io/blog/2025/12/29/custom-waterboarding.html"><![CDATA[<p>My wife likes to paint watercolor pictures using certain small sizes of paper, so as a Christmas gift, I made some custom laser-engraved acrylic panels to use as desktop easel surfaces.</p>

<h2 id="the-goal">the goal</h2>

<p>She uses a handful of different specific sizes of paper, and tapes them down to a flat surface with painter’s tape. The tape needs to be well levelled and centered, so that the paintings have a nice border afterwards.</p>

<p>She’s been using cardboard, but it gets wet and warps, so we wanted something that would stay flat. I also wanted to add special markings to help with the alignment - some boxes that match the paper sizes, and some general grid-lines for lining up the tape and providing flexibility to be used with other sizes.</p>

<h2 id="first-draft">first draft</h2>

<p>I quickly sketched up a basic rectangle with rounded corners and some patterned grid-lines in fusion360 and exported to svg, then manually edited the svg to have the borders be a different color than the grid-lines, so I could differentiate cutting and engraving in LightBurn.</p>

<p>I realized there would be a problem… Acrylic plates come with some protective adhesive on them to be peeled off after cutting, and this would have meant peeling off hundreds of tiny squares. It’s frustrating to peel off even one solid piece of this film - I don’t recommend it.</p>

<p>So I decided to just use the perforation mode in LightBurn to make the grid-lines dashed. They were 1/4” apart, and the setting was in mm so I lazily did 3mm (approximately but not quite 1/8”).</p>

<p><img src="./img/1.jpg" alt="" /></p>

<p>Thankfully the it was easy enough to peel the film off mostly in one piece.</p>

<p><img src="./img/2.jpg" alt="" /></p>

<p>This approximation made it look a little funny since it was staggered, but the result was pretty good and definitely usable!</p>

<p><img src="./img/3.jpg" alt="" /></p>

<h2 id="better-lines">better lines</h2>

<p>I wanted to make the grid-lines look nicer, so I did an actual “+” shape and patterned that across the whole surface. But then I ran into an issue… Every time I tried to export it to svg from fusion using the shaper-origin plugin, it would crash. I think it was just too many lines… rather than <code class="language-plaintext highlighter-rouge">m+n</code>, it was <code class="language-plaintext highlighter-rouge">2*m*n</code>.</p>

<p>Instead. I just exported a sketch with a single “+” symbol, and had to tinker around with the svg file to figure out the placement and units. Then I converted it to a jinja template and just used simple for-loops to manually pattern the “+” shape.</p>

<p>The svg template file and the command to generate it are in a little repo <a href="https://github.com/r-downing/paintboard">here</a></p>

<p>The final product looks much nicer!</p>

<p><img src="./img/4.jpg" alt="" /></p>]]></content><author><name></name></author><category term="laser-cutting" /><category term="fusion360" /><category term="svg" /><category term="jinja2" /><category term="python" /><summary type="html"><![CDATA[My wife likes to paint watercolor pictures using certain small sizes of paper, so as a Christmas gift, I made some custom laser-engraved acrylic panels to use as desktop easel surfaces.]]></summary></entry><entry><title type="html">running bash commands in jekyll (plus git commit info)</title><link href="https://ryand.io/blog/2025/12/27/bash-commands-in-jekyll.html" rel="alternate" type="text/html" title="running bash commands in jekyll (plus git commit info)" /><published>2025-12-27T00:00:00+00:00</published><updated>2025-12-27T00:00:00+00:00</updated><id>https://ryand.io/blog/2025/12/27/bash-commands-in-jekyll</id><content type="html" xml:base="https://ryand.io/blog/2025/12/27/bash-commands-in-jekyll.html"><![CDATA[<p>I started vibe-coding a little jekyll extension in Ruby to embed the git commit sha and timestamp into the blog, then accidentally came up with something even cooler.</p>

<h2 id="the-original-goal---git-info-in-the-jekyll-build-output">the original goal - git info in the jekyll build output</h2>

<p>When I push a change to the site, github takes a minute to build and publish the new version. I have to either manually navigate to the github page and watch the build-status, or refresh the webpage over and over to see if it’s changed yet, and make sure the browser isn’t caching it, etc… And for subtle or invisible changes, this can be even trickier to tell if it’s changed yet.</p>

<p>I wanted to be able to have the sha and timestamp from the git commit embedded somewhere in the webpage where I could quickly check it.</p>

<p>I frequently embed the short commit hash in the build artifacts of other projects I work in, even the firmware ones. I find that it’s a more reliable way to track what code a software build was made from than a build number (which can be arbitrary and require manual association with a commit) or a version number (which typically requires manual updating and only gets changed at a formal release time). With this I can literally generate a URL that links back to that commit on github.</p>

<p>I also like to append a <code class="language-plaintext highlighter-rouge">-dirty</code> suffix to the sha if there are any untracked changes.</p>

<h2 id="the-original-solution">the original solution</h2>

<p>Since I’m not familiar with Ruby, I used a little extra AI help to quickly figure out the script. It was also helpful for figuring out the exact git log commands to get the timestamp in my preferred timezone.</p>

<div>
For now it's on the <a href="/blog/about">about</a> page so I can be sure of what version of the site I am looking at.
</div>

<h3 id="the-git-jekyll-code">the git jekyll code</h3>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Jekyll</span>
  <span class="k">class</span> <span class="nc">GitCommitGenerator</span> <span class="o">&lt;</span> <span class="no">Generator</span>
    <span class="n">priority</span> <span class="ss">:highest</span>
    <span class="k">def</span> <span class="nf">generate</span><span class="p">(</span><span class="n">site</span><span class="p">)</span>
      <span class="n">commit_hash</span> <span class="o">=</span> <span class="no">ENV</span><span class="p">[</span><span class="s1">'JEKYLL_BUILD_REVISION'</span><span class="p">]</span> <span class="o">||</span> <span class="sb">`git rev-parse --short HEAD`</span><span class="p">.</span><span class="nf">strip</span>
      <span class="k">if</span> <span class="o">!</span><span class="sb">`git status --short`</span><span class="p">.</span><span class="nf">strip</span><span class="p">.</span><span class="nf">empty?</span>
        <span class="n">commit_hash</span> <span class="o">+=</span> <span class="s2">"-dirty"</span>
      <span class="k">end</span>
      <span class="n">site</span><span class="p">.</span><span class="nf">config</span><span class="p">[</span><span class="s1">'commit_hash'</span><span class="p">]</span> <span class="o">=</span> <span class="n">commit_hash</span>
      <span class="n">site</span><span class="p">.</span><span class="nf">config</span><span class="p">[</span><span class="s1">'commit_timestamp'</span><span class="p">]</span> <span class="o">=</span> <span class="sb">`TZ="America/New_York" git log -1 --format=%cd --date=iso-local`</span><span class="p">.</span><span class="nf">strip</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>

<h2 id="the-next-goal---embedding-code">the next goal - embedding code</h2>

<p>While starting to write this blog post, I was trying to figure out how best to embed or include the plugin code into the post. I <em>could have</em> just copied and pasted the code, as it currently is, into this post inside a code tag and be done with it…</p>

<p>But I have the file right here - why can’t I embed it somehow? However, since it’s in a directory with an underscore, jekyll won’t include it in the output by default.</p>

<p>Maybe I could just include the plugins folder manually? But that seems too heavy-handed, and I don’t want to be dumping other unnecessary files into the build output.</p>

<p>Since I’m including files relative to my posts with the jekyll-postfiles extension, maybe I could just symlink the file into this directory? Nah, that didn’t seem to work - the symlink was getting copied instead of the file… Maybe I could go the other way around, and have the actual code in this directory and have a symlink in the plugins folder to the file here? But that seems like poor organization and pretty brittle to have my actual code living inside some random blog post.</p>

<p>I started exploring some other relative-include solutions and found one that mentioned executables. Hmm, this got me thinking - could I just call <code class="language-plaintext highlighter-rouge">cat _plugins/...</code> from within the jekyll file? Or any other bash command?</p>

<p>Imagine the possibilities… I could invoke some build steps in other languages, or even fetch remote content and pipe it right into my markdown.</p>

<h2 id="the-bonus-solution---executing-system-commands-from-within-jekyll">the bonus solution - executing system commands from within jekyll</h2>

<p>Here’s the code I came up with to create a <code class="language-plaintext highlighter-rouge">run_cmd</code> liquid tag that allows me to straight-up run commands and put their stdout output in the pre-rendered jekyll files.</p>

<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">module</span> <span class="nn">Jekyll</span>
  <span class="k">class</span> <span class="nc">RunCommandTag</span> <span class="o">&lt;</span> <span class="no">Liquid</span><span class="o">::</span><span class="no">Tag</span>
    <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">tag_name</span><span class="p">,</span> <span class="n">command</span><span class="p">,</span> <span class="n">tokens</span><span class="p">)</span>
      <span class="k">super</span>
      <span class="vi">@command</span> <span class="o">=</span> <span class="n">command</span><span class="p">.</span><span class="nf">strip</span>
    <span class="k">end</span>

    <span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="n">context</span><span class="p">)</span>
      <span class="sb">`</span><span class="si">#{</span><span class="vi">@command</span><span class="si">}</span><span class="sb">`</span><span class="p">.</span><span class="nf">rstrip</span>
    <span class="k">rescue</span> <span class="o">=&gt;</span> <span class="n">e</span>
      <span class="s2">"Error executing command: </span><span class="si">#{</span><span class="n">e</span><span class="p">.</span><span class="nf">message</span><span class="si">}</span><span class="s2">"</span>
    <span class="k">end</span>
  <span class="k">end</span>
<span class="k">end</span>

<span class="no">Liquid</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">register_tag</span><span class="p">(</span><span class="s1">'run_cmd'</span><span class="p">,</span> <span class="no">Jekyll</span><span class="o">::</span><span class="no">RunCommandTag</span><span class="p">)</span>
</code></pre></div></div>

<p>And here’s the markdown/liquid i had to write to generate the code block above:</p>

<div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code>```ruby
<span class="cp">{%</span><span class="w"> </span><span class="nt">run_cmd</span><span class="w"> </span><span class="nv">cat</span><span class="w"> </span>_plugins/run_cmd.rb<span class="w"> </span><span class="cp">%}</span>
```
</code></pre></div></div>

<p>Side-note - to generate this second code block, I had to escape the liquid using <code class="language-plaintext highlighter-rouge">raw</code> / <code class="language-plaintext highlighter-rouge">endraw</code>.</p>

<p>I could even use this to replace the git plugin I just made. I’ll get around to that later…</p>

<p>And just for the hell of it, here’s the output of the <code class="language-plaintext highlighter-rouge">grep --version</code> command for the runner that’s built the file you’re reading right now (e.g. <code class="language-plaintext highlighter-rouge">run_cmd grep --version</code> wrapped in liquid brackets, wrapped in a markdown code fence):</p>

<pre><code class="language-txt">grep (GNU grep) 3.11
Copyright (C) 2023 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &lt;https://gnu.org/licenses/gpl.html&gt;.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Mike Haertel and others; see
&lt;https://git.savannah.gnu.org/cgit/grep.git/tree/AUTHORS&gt;.

grep -P uses PCRE2 10.42 2022-12-11
</code></pre>

<h3 id="some-security-considerations">some security considerations</h3>

<p>I did a quick test to make sure that a <code class="language-plaintext highlighter-rouge">run_cmd ...</code> invocation that outputs another <code class="language-plaintext highlighter-rouge">run_cmd ...</code> won’t be recursively evaluated. If it did, and my command involved fetching some external file, a <a href="https://en.wikipedia.org/wiki/Rob_Schneider">bad actor</a> could modify that external file to cause my builder to run some arbitrary commands. But thankfully that’s not the case.</p>

<h3 id="some-performance-considerations">some performance considerations</h3>

<p>If I include a file using another liquid directive which includes a run_cmd, then that <strong>would</strong> get evaluated, which is nice. But this means if I were to use a run_cmd in a common file that’s included in multiple places, such as <code class="language-plaintext highlighter-rouge">_includes/footer.html</code>, then the command would be invoked multiple times, once for each file that includes the footer. So this kind of filter which runs in the pre-rendered stage should be used mainly in the lowest-level output files.</p>]]></content><author><name></name></author><category term="git" /><category term="bash" /><category term="linux" /><category term="jekyll" /><category term="liquid" /><category term="commit" /><category term="ruby" /><category term="blog" /><summary type="html"><![CDATA[I started vibe-coding a little jekyll extension in Ruby to embed the git commit sha and timestamp into the blog, then accidentally came up with something even cooler.]]></summary></entry><entry><title type="html">css text-wrap:balance for pretty little blurbs</title><link href="https://ryand.io/blog/2025/12/21/css-text-wrap-balance.html" rel="alternate" type="text/html" title="css text-wrap:balance for pretty little blurbs" /><published>2025-12-21T00:00:00+00:00</published><updated>2025-12-21T00:00:00+00:00</updated><id>https://ryand.io/blog/2025/12/21/css-text-wrap-balance</id><content type="html" xml:base="https://ryand.io/blog/2025/12/21/css-text-wrap-balance.html"><![CDATA[<p>Found a somewhat-recent (<a href="https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/text-wrap">2024</a>) nice little CSS feature for balanced text-wrapping.</p>

<p>I am by no means a CSS expert. I know just enough to have an idea of what <em>should</em> be possible, and drive myself insane trying to figure out how to do it.</p>

<p>I was working on adding next/previous post links to the bottom of the blog post layout, and I came across this feature which I think makes it look a lot nicer.</p>

<p>The next-post link is right aligned with a little right-arrow ⇒ after the title. If the screen is shrunken just right, then the arrow ends up on its own line, which looks ugly. This tries to balance the number of characters per line. It’s apparently computationally more intensive for browsers and limited to a handful of lines. But this is exactly the use case I imagine it would be for</p>

<h2 id="examples">examples</h2>

<p>some quick inline CSS examples</p>

<h3 id="without-text-wrap-balance">without <code class="language-plaintext highlighter-rouge">text-wrap: balance;</code></h3>

<p><code id="example1-code"></code></p>

<div id="example1" style="border: 1px solid gray; max-width: 15em; text-align: right;">a long titled link to the next post &rArr;</div>

<h3 id="with-text-wrap-balance">with <code class="language-plaintext highlighter-rouge">text-wrap: balance;</code></h3>

<p><code id="example2-code"></code></p>

<div id="example2" style="border: 1px solid gray; max-width: 15em; text-align: right; text-wrap: balance;">a long titled link to the next post &rArr;</div>

<script>
    document.querySelector("#example1-code").innerText = document.querySelector("#example1").outerHTML;
    document.querySelector("#example2-code").innerText = document.querySelector("#example2").outerHTML;
</script>

<noscript>need javascript enabled to populate the example code.</noscript>

<h2 id="conclusion">conclusion</h2>

<p>Here’s a screenshot from the blog on a simulated Iphone SE:</p>

<p><img src="./screenshot.png" alt="screenshot" /></p>

<p>Or see it action by scrolling to the bottom of this page and making the window smaller.</p>]]></content><author><name></name></author><category term="css" /><category term="blog" /><category term="web-dev" /><category term="responsive" /><summary type="html"><![CDATA[Found a somewhat-recent (2024) nice little CSS feature for balanced text-wrapping.]]></summary></entry></feed>