<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Calvin's Pizza]]></title><description><![CDATA[proof that (sometimes) I make things]]></description><link>https://calvins.pizza/</link><image><url>https://calvins.pizza/favicon.png</url><title>Calvin&apos;s Pizza</title><link>https://calvins.pizza/</link></image><generator>Ghost 5.82</generator><lastBuildDate>Mon, 20 Apr 2026 07:02:43 GMT</lastBuildDate><atom:link href="https://calvins.pizza/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Making a 1U Crossfader]]></title><description><![CDATA[<p>I&apos;ve been trying to finish up the last row (er, row and a third) of a eurorack drum machine for a long while now. The other week I finally got the actual case and racked&amp;routed everything up.</p><p>The machine is itself is based around an 8-channel</p>]]></description><link>https://calvins.pizza/1u-crossfader/</link><guid isPermaLink="false">682a10e1454dd8033dd65944</guid><category><![CDATA[eurorack]]></category><category><![CDATA[projects]]></category><category><![CDATA[synth]]></category><category><![CDATA[3dprinting]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 18 May 2025 18:08:12 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2025/05/PXL_20250517_160516778_crop.png" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160516778_crop.png" alt="Making a 1U Crossfader"><p>I&apos;ve been trying to finish up the last row (er, row and a third) of a eurorack drum machine for a long while now. The other week I finally got the actual case and racked&amp;routed everything up.</p><p>The machine is itself is based around an 8-channel gate &quot;bus,&quot; which is really all to say that it&apos;s built for triggering 8 simultaneous drum sounds. These are by default allocated to <a href="https://wmdevices.com/collections/eurorack-modules-1/products/crater?ref=calvins.pizza" rel="noreferrer">Kick</a>, <a href="https://wmdevices.com/collections/eurorack-modules-1/products/kraken?ref=calvins.pizza" rel="noreferrer">Snare</a>, Hat (closed), Hat (open), <a href="https://www.ericasynths.lv/shop/eurorack-modules/by-series/drum-series/toms/?ref=calvins.pizza" rel="noreferrer">Tom 1, Tom2</a>, <a href="https://wmdevices.com/collections/eurorack-modules-1/products/fracture?ref=calvins.pizza" rel="noreferrer">Clap</a>, <a href="https://wmdevices.com/collections/eurorack-modules-1/products/crucible?ref=calvins.pizza" rel="noreferrer">Cymbal</a> using the wonderful drum modules from <a href="https://wmdevices.com/collections/eurorack-modules-1?ref=calvins.pizza" rel="noreferrer">WMD</a> and <a href="https://www.ericasynths.lv/shop/eurorack-modules?ref=calvins.pizza" rel="noreferrer">Erica</a>.</p><p>Speaking of Erica, when they released the <a href="https://www.ericasynths.lv/shop/eurorack-modules/by-series/drum-series/perkons-voice/?ref=calvins.pizza" rel="noreferrer">Perkons Voice</a> I got the GAS (Gear Acquisition Syndrome) bad. Still haven&apos;t picked one up but I loved the sounds of the <a href="https://www.ericasynths.lv/shop/standalone-instruments-1/perkons-hd-01-black/?ref=calvins.pizza" rel="noreferrer">Perkons Drums machine</a> and this would be an awesome way to get the sound into my own workflow.....I was worried about how it would fit into the signal path of my drum machine though. I had the actual <em>room</em> in the case to fit it but how could/should I incorporate it into the actual signal flow since all 8 of my gates were currently spoken for?</p><p>The way I saw it, I had a couple options:</p><ul><li>do nothing, and just manually re-patch the Perkons Voice in as I need it (un-patching another drum in the bus)</li><li>build or buy a little switch so that the Perkons Voice could be swappable with a single voice easily (e.g, flip a switch and the gate that was triggering the Snare is now triggering Perkons Voice)</li><li>build or buy a couple little crossfaders so that I could &quot;inject&quot; the Perkons Voice into the signal path of another drum and fade between them</li></ul><p>I liked the last option the best even though it involved building or acquiring more modules. What it does allow is for the Perkons Voice to either be <em>blended</em> with a voice or replace it...but for it to work best every drum voice that I might want to blend with the Perkons would need a crossfader placed after it.</p><p>To save on costs I figured I&apos;d build them myself, then I looked at PCB prices with current economic uncertainty and tariffs. Untenable.</p><p>So to save further I decided I&apos;d just use some protoboard and 3D print a shitty face plate, hoping I could scrounge the parts I needed from what I already had in the bins. Let&apos;s get started!</p><p>Starting off I used <a href="https://www.instructables.com/Crossfader-Circuit-Point-to-Point/?ref=calvins.pizza" rel="noreferrer">this Instructables by ozerik</a> as a schematic reference</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/05/1U-cross-fader---page-2.png" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="1872" height="1404" srcset="https://calvins.pizza/content/images/size/w600/2025/05/1U-cross-fader---page-2.png 600w, https://calvins.pizza/content/images/size/w1000/2025/05/1U-cross-fader---page-2.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/1U-cross-fader---page-2.png 1600w, https://calvins.pizza/content/images/2025/05/1U-cross-fader---page-2.png 1872w" sizes="(min-width: 720px) 720px"></figure><p>This&apos;ll work well for the intended application; it does invert the signal which is fine for audio but if we were using this to mix control voltage it would obviously not be ideal. I also only had a 50k pot lying around so I had to go with that instead of something like 20k which probably would have been better. Otherwise I had the parts!</p><p>I was going to make this a 1U module which means the PCB can&apos;t be taller than 22.5mm. First thing to do was try and figure out how to fit everything in that size</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250515_200239538.jpg" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="2000" height="1506" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250515_200239538.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250515_200239538.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250515_200239538.jpg 1600w, https://calvins.pizza/content/images/2025/05/PXL_20250515_200239538.jpg 2000w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_154501840.jpg" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_154501840.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_154501840.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_154501840.jpg 1600w, https://calvins.pizza/content/images/2025/05/PXL_20250517_154501840.jpg 2000w" sizes="(min-width: 720px) 720px"></figure><p>Naturally I had to split the circuit into two boards stacked vertically to maintain a reasonable width. This is pretty typical in eurorack design so no big deal. We&apos;ll have one for the interface elements (jacks, knobs) and one that has the power header and op-amp package.</p><p>Once I got the interface elements placed on a board in an ergonomic way I had to start sketching out the &quot;traces&quot; for how everything would connect. This is definitely where you miss going through the PCB design process since the software to turn a schematic into a PCB has a lot of helpful features and error checking even if it does require a lot of set up. Instead I had to stare at this over and over after a couple context breaks just to be sure everything was right. Once the soldering started going back and fixing any mistakes would be <em>really</em> unfun so I did not want to beef it in the planning steps.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2025/05/motherboard_design.png" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="1214" height="747" srcset="https://calvins.pizza/content/images/size/w600/2025/05/motherboard_design.png 600w, https://calvins.pizza/content/images/size/w1000/2025/05/motherboard_design.png 1000w, https://calvins.pizza/content/images/2025/05/motherboard_design.png 1214w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">well, that looks messy haha</span></figcaption></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/05/control_board_design.png" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="1342" height="912" srcset="https://calvins.pizza/content/images/size/w600/2025/05/control_board_design.png 600w, https://calvins.pizza/content/images/size/w1000/2025/05/control_board_design.png 1000w, https://calvins.pizza/content/images/2025/05/control_board_design.png 1342w" sizes="(min-width: 720px) 720px"></figure><p>One thing I was <em>super</em> worried about getting the pins that connect the boards correct. It felt like it would be so easy during this phase <em>or</em> the building phase to forget what side of the board I&apos;m looking at for any given node and put something in the wrong spot. Fingers crossed!</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_114645763.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_114645763.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_114645763.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_114645763.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_114645763.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_120420069.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_120420069.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_120420069.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_120420069.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_120420069.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_120432039.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_120432039.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_120432039.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_120432039.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_120432039.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_131427208.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_131427208.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_131427208.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_131427208.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_131427208.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_131440460.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_131440460.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_131440460.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_131440460.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_131440460.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>Main board wired up! Onto the interface board, luckily much simpler.</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_140808168.MP.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_140808168.MP.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_140808168.MP.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_140808168.MP.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_140808168.MP.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_140817769.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_140817769.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_140817769.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_140817769.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_140817769.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_154506786.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_154506786.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_154506786.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_154506786.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_154506786.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>I almost did forget a power conditioning capacitor, quickly added that and smooshed the boards together:</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160022588.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160022588.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160022588.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160022588.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160022588.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160204927.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160204927.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160204927.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160204927.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160204927.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160211458.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160211458.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160211458.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160211458.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160211458.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>For the faceplate I just quickly got something drawn up in <a href="https://openscad.org/?ref=calvins.pizza" rel="noreferrer">openSCAD</a></p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/05/openscad_screenshot.png" class="kg-image" alt="Making a 1U Crossfader" loading="lazy" width="1390" height="900" srcset="https://calvins.pizza/content/images/size/w600/2025/05/openscad_screenshot.png 600w, https://calvins.pizza/content/images/size/w1000/2025/05/openscad_screenshot.png 1000w, https://calvins.pizza/content/images/2025/05/openscad_screenshot.png 1390w" sizes="(min-width: 720px) 720px"></figure><p>and after a few iterations to nudge everything in the right place....</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160516778_crop-1.png" width="2000" height="1150" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160516778_crop-1.png 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160516778_crop-1.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160516778_crop-1.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160516778_crop-1.png 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160521404.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160521404.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160521404.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160521404.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160521404.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2025/05/PXL_20250517_160604317.jpg" width="2000" height="2656" loading="lazy" alt="Making a 1U Crossfader" srcset="https://calvins.pizza/content/images/size/w600/2025/05/PXL_20250517_160604317.jpg 600w, https://calvins.pizza/content/images/size/w1000/2025/05/PXL_20250517_160604317.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2025/05/PXL_20250517_160604317.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2025/05/PXL_20250517_160604317.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>It fits! It powers on! It works! Here&apos;s me crossfading between a snare and a kick drum as proof of life.</p><figure class="kg-card kg-video-card kg-width-regular kg-card-hascaption" data-kg-thumbnail="https://calvins.pizza/content/media/2025/05/crossfader_demo_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/05/crossfader_demo.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/05/crossfader_demo_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:29</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            <figcaption><p><span style="white-space: pre-wrap;">Probably would have been better to use sounds more distinguishable by waveshape or at least zoomed out on the scope a little whoops</span></p></figcaption>
        </figure><p>Now I just need to make like 2 more...</p>]]></content:encoded></item><item><title><![CDATA[3D printing a HOTAS]]></title><description><![CDATA[stumbling through 3D printing a HOTAS to play Elite Dangerous]]></description><link>https://calvins.pizza/3d-printing-a-hotas/</link><guid isPermaLink="false">67a68e15454dd8033dd6586b</guid><category><![CDATA[dev]]></category><category><![CDATA[projects]]></category><category><![CDATA[3dprinting]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sat, 08 Feb 2025 00:53:38 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2025/02/PXL_20230412_213929541.jpg" medium="image"/><content:encoded><![CDATA[<h3 id="content">Content</h3><ul><li><a href="#intro" rel="noreferrer">intro</a></li><li><a href="#the-joystick-build" rel="noreferrer">the joystick build</a></li><li><a href="#the-throttle-build" rel="noreferrer">the throttle build</a></li><li><a href="#the-macro-pad" rel="noreferrer">the macropad</a></li><li><a href="#mounting-everything" rel="noreferrer">mounting everything</a></li><li><a href="https://github.com/CMorooney/hotas?ref=calvins.pizza" rel="noreferrer">arduino code</a> (utilizing <a href="https://github.com/bsmr/MHeironimus-ArduinoJoystickLibrary?ref=calvins.pizza" rel="noreferrer">this joystick library</a>)</li></ul><h2 id="intro">Intro</h2><img src="https://calvins.pizza/content/images/2025/02/PXL_20230412_213929541.jpg" alt="3D printing a HOTAS"><p>I have a friend who got me into <a href="https://www.nomanssky.com/?ref=calvins.pizza">No Man&apos;s Sky</a> many years ago. I still really love that game and the team who makes it and I often go back for more --</p><p>But as anyone with a passing interest knows, the space simulators are numerous. Another friend got deep into <a href="https://www.elitedangerous.com/?ref=calvins.pizza">Elite Dangerous</a> and had been evangelizing it to me for years, often telling funny stories of emergent or in-game events and showing off some truly beautiful screenshots.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2025/02/image.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1920" height="1080" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image.png 1600w, https://calvins.pizza/content/images/2025/02/image.png 1920w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">an elite dangerous screenshot from my buddy</span></figcaption></figure><p>For some reason or another, I finally caved...Perhaps it was because picking up the game would mean having an excuse to see if I could print and wire up a full HOTAS (Hands On Stick And Throttle). Elite Dangerous is arguably more of a space&#xA0;<strong>flight</strong>&#xA0;simulator for a lot of the gameplay so I thought having these sort of controls would be super fun to learn.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2025/02/image-1.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="900" height="900" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-1.png 600w, https://calvins.pizza/content/images/2025/02/image-1.png 900w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">a commercial HOTAS for flight sims</span></figcaption></figure><p>It&apos;s probably not worth going into examples of how complicated and expensive a sturdy pre-built and designed HOTAS might be...and suffice it to say I had the hubris to immediately think I could slap an arduino in a printed shell and be done with it. I didn&apos;t have a lot of an idea of what I needed, so my only requirements were that I had a joystick with&#xA0;<em>some</em>&#xA0;buttons and a throttle and that both should report their rotation axis&apos; using magnetic hall effect sensors for minimal wear &amp; tear.</p><h2 id="the-joystick-build">The Joystick build</h2><p>Naturally we&apos;re standing on a lot of shoulders here; I was lucky to find&#xA0;<a href="https://hotas.miraheze.org/wiki/3D_Printing?ref=calvins.pizza" rel="noopener nofollow">this small but helpful wiki</a>&#xA0;purely for 3D printing flight sim gear. Through that I discovered the apparently popular&#xA0;<a href="https://www.thingiverse.com/thing:2496028?ref=calvins.pizza" rel="noopener nofollow">Olukelo Gimbal</a>&#xA0;&#x2013; a 2 axis joystick gimbal.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-2.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="797" height="712" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-2.png 600w, https://calvins.pizza/content/images/2025/02/image-2.png 797w" sizes="(min-width: 720px) 720px"></figure><p>For the actual Joystick and Throttle I ended up finding a creator on&#xA0;<a href="https://cults3d.com/?ref=calvins.pizza" rel="noopener nofollow">Cults3D</a>&#xA0;who designed what looked to me to be pretty awesome gear. I could see the Olukelo Gimbal in the photos for the&#xA0;<a href="https://cults3d.com/en/3d-model/gadget/joystick-hotas-flight-stick?ref=calvins.pizza" rel="noopener nofollow">Joystick</a>&#xA0;so I knew it would fit somehow and the purly rendered photos of the&#xA0;<a href="https://cults3d.com/en/3d-model/game/throttle-hotas-box?ref=calvins.pizza" rel="noopener nofollow">Throttle</a>&#xA0;made it look very cool and well thought out. That&apos;s honestly&#xA0;<em>about</em>&#xA0;as much thought as I put into it since I have no real flight sim experience... these looked &quot;good enough&quot; (well, they look great) and had at least some documentation on the build. Thanks&#xA0;<a href="https://cults3d.com/en/users/Miso988/creations?ref=calvins.pizza" rel="noopener nofollow">Miso988</a>!</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-4.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2667" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-4.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-4.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-4.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-4.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-3.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1518" height="733" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-3.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-3.png 1000w, https://calvins.pizza/content/images/2025/02/image-3.png 1518w" sizes="(min-width: 720px) 720px"></figure><p>Get ready for some 90&apos;s Nickelodeon colors, because that&apos;s the filment I had most of the time I was working on this build &#x2013; first up was the gimbal because I wasn&apos;t sure if my crappy little printer could print something &quot;this mechanical.&quot; I&apos;ve really only ever printed keyboard parts and other small, static things.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-5.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-5.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-5.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-5.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-5.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230330_204339645_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230330_204339645.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230330_204339645_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:15</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>So yeah, it actually went really well! this gimbal was a neat little design and I&apos;m really glad I got to put it together like this. You&#xA0;<em>might</em>&#xA0;have noticed in that video but there&apos;s already a little cavity in the center of the main axis bearing carriers for little cylindrical magnets -- that&apos;s where we&apos;ll measure the rotation for the arduino controller.</p><p>Onto the actual stick! It doesn&apos;t look like anything to me!</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-6.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-6.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-6.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-6.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-6.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>I gave it a light (er, shitty) sand to soften it up a tad. There was also this little thumb button (the green one in the pictures) that was supposed to slide into this spot with this little collar and &#x2013; well I was a little incredulous it was actually going to sit in there. So I tested that here as well as the cable routing through the gimbal. Foreshadowing: 2 wires for one button as pictured here is a dumb strategy and there&apos;s gonna be more of it before there&apos;s less.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230330_204251036_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230330_204251036.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230330_204251036_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:17</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Look -- it&apos;s starting to seem familiar! As a joystick...not the other thing.</p><p>The top of the stick (where most of the buttons will be) wasn&apos;t too bad, though I did hate soldering these push buttons and then trying to slide them into the little jig for the directional input in the center here:</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230407_214705615_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230407_214705615.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230407_214705615_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:06</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>The rest of the top is split in half so that you can install a little leaf switch for the main trigger, which has a satisfying click:</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230331_180912500_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230331_180912500.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230331_180912500_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:03</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>There is a secondary trigger that I had to set similarly, thought this will sit at the bottom of the shaft, er..stick.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230331_174520039_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230331_174520039.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230331_174520039_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:04</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Here&apos;s me holding it where it&apos;ll end up for proof:</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230331_174714038_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230331_174714038.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230331_174714038_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:08</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Then it was time to screw all those parts together!</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230331_221112442_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230331_221112442.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230331_221112442_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:21</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Now I had already started to sweat on the number of wires coming out of this thing &#x2013; for some reason I sent two wires out per switch just out of some kind of weird or bad habit.</p><p>Sure enough, this bundle was too thick to get through the gimbal channel. Time to take it all apart and rewire the buttons so that one lug of each button was tied to one single common wire inside the stick.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-7.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="400" height="167"></figure><p>This would allow me to use the buttons as ACTIVE LOW inputs to the logic I would program later.</p><p>Basically, we can take that common wire that all switches are connected to and send one wire through the channel to connect that to ground.</p><p>In the arduino code we will then set the button input pins to use an internal pullup resistor to tigh those inputs HIGH be default. Then, when the button for any given pin is pushed, it will shift from that tied HIGH to the common ground wire.</p><p>This allows us to check if arduino pins are LOW instead of high to know if a button is pressed, but more importantly cuts our wire bundle from the stick in half.</p><p>Probably the only picture I have of this ordeal... but hey there are less wires!</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-8.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-8.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-8.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-8.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-8.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>And they all fit! got the joystick on the gimbal and programmed the buttons to test all the connections and the code (I&apos;ll share the link to all that below).</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-9.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-9.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-9.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-9.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-9.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>The buttons work! using a simple game tester site to make sure.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230412_213851482_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230412_213851482.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230412_213851482_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:15</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Okay so that was all great news...but to be honest I still hadn&apos;t decided or figured out how I was going to do the hall effect stuff for the actual joystick axis, arguably the most crucial part of the build.</p><p>Orginally I bought some&#xA0;<code>SS495A</code>&#xA0;Linear hall effect sensors, thinking I just needed anything with an analog output but of course that was under thinking it a bit.</p><p>The other main way the&#xA0;<code>SS495A</code>&#xA0;packages work is that they detect magnetic poles from the front of the little transister-esque body. As you approach the front of the package with one end of a cylindrical magnet (the kind we are embedding in our bearing carriers) the signal voltage goes toward the positive voltage rail. Approaching with the other end of the magnet, and the signal voltage goes toward ground.</p><p>There is no way to mount this sensor in such a way that it will work for our use case, however. Our magnets are not&#xA0;<em>approaching</em>&#xA0;our sensor no matter how we mount them -- they aren&apos;t really&#xA0;<em>approaching</em>&#xA0;anything. They&#xA0;<em>rotate</em>&#xA0;inside the bearing carriers.</p><p>So the&#xA0;<code>SS495A</code>&#xA0;was the wrong part for the job. After some searching however I did find a different package that was still in production, the&#xA0;<code>AS5600</code>. This is a rotary position sensor for magnets and is meant to be used for contactless knobs and encoders, but it should work perfectly for our purposes as well.</p><p>When they finally arrived the analog output was busted on the board that was sent over...big box stores and their bullshit... Luckily clipping out a resistor that fixed that hah.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230415_231838856_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230415_231838856.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230415_231838856_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:05</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>My new problem was mounting these on the gimbal securely. they were kind of a perfect size to just be slapped on top of the bearing carriers so the chip sat right over the magnets, but I decided to print new carries so that I could mount it properly &amp; securly (after attaching it to a protoboard to give it some width).</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-10.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-10.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-10.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-10.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-10.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-11.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-11.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-11.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-11.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-11.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230418_182922463_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230418_182922463.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230418_182922463_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:04</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230418_183551178_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230418_183551178.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230418_183551178_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:03</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Once I finally got these mounted I slapped the gimbal back together with these new bearing carriers and testing right on the scope &#x2013; success!!</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230418_205857797_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230418_205857797.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230418_205857797_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:12</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>I got the other axis wired up anddd</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230419_010602725_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230419_010602725.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230419_010602725_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:27</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Flight! Now onto the throttle....</p><h2 id="the-throttle-build">The Throttle build</h2><p>The throttle as modeled has two axis and, lucky for me, is designed for the type of package that those&#xA0;<code>SS495A</code>&#xA0;linear hall effect sensors are! These little square magnets sit between the columns and must be placed correctly so that opposing poles are facing &quot;inward&quot; of the little magnet mounting piece.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-12.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-12.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-12.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-12.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-12.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>The&#xA0;<code>SS495A</code>&#xA0;gets glued in this little channel and given some longer leads for the rest of the way out.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-13.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-13.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-13.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-13.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-13.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>Slather it with some hot glue so it doesn&apos;t move in there....</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-14.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-14.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-14.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-14.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-14.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-15.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-15.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-15.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-15.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-15.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>I could then thread &amp; mount these together and in the box! I would later weight this down so the top heaviness of it all would be less of an issue</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230414_201904942_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230414_201904942.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230414_201904942_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:14</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Overall the throttle was a lot less painful than the Stick since there&apos;s no real gimbal to worry about and the hall effect design was more straight-forward. However, there are a&#xA0;<em>lot</em>&#xA0;more of those directional &quot;hats&quot; on the throttle control which meant more delicate wire soldering for small push buttons.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-16.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-16.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-16.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-16.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-16.png 2400w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-17.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-17.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-17.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-17.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-17.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>But I managed to get it all in there (with some more hot glue, of course)</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230420_011741602_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230420_011741602.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230420_011741602_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:21</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>You might see there I&apos;ve also added the triggers to the posts which will push those buttons on the bottom of the grips that you can kinda see in that last picture.</p><p>Then I could screw the actual grips on the posts!</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230420_214927675_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230420_214927675.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230420_214927675_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:25</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Cool, now I just gotta get all those wires to another arduino... I ended up using a ribbon cable this time so that the arduino board could just be soldered to a header and the rest could be a little more modular. I would eventually go back and re-do the end of the Stick wiring to use the same strategy.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230506_202318094_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230506_202318094.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230506_202318094_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:08</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-18.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-18.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-18.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-18.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-18.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>then I tied the wires up and added a bunch of tire weights to the bottom of the box where there was still room to balance the weight out.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-19.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-19.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-19.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-19.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-19.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>I ended up going into Blender and splitting the top plate of the throttle into two so I could get it on...I didn&apos;t think too hard about how that should have all worked and honestly this solution is fine for me. But having that top plate allowed me to also install the designed &quot;stoppers&quot; which was useful to me for a few reasons &#x2013; mostly though the hall effect sensors were working great but at some point in the back-travel they would flip power rails and I didn&apos;t want to take this all apart and try to sort that (or, hell, try and code for it. That&apos;s some &apos;fix it in post&apos; energy).</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230502_204303333_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230502_204303333.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230502_204303333_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:09</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Also at this point I shoved a rod into an open hole on both the throttle posts to &quot;join&quot; the axis together and ended up cutting one of the hall effect sensors out of the arduino code entirely simply because having 2 thrust axis in Elite Dangerous wouldn&apos;t make a ton of sense. I can always remove this post and put the other axis back in the code if I need to.</p><p>But that was it for the throttle! Not as much re-doing or experimentation as the stick which was a nice change of pace.</p><h2 id="the-macro-pad">The Macro pad</h2><p>There are a&#xA0;<em>lot</em>&#xA0;of mappable controls in Elite Dangerous and it&apos;s pretty nice to have quick access to many of them, so I also decided to create a small macropad for anything else I would want a button for.</p><p>I also really wanted to try out these really cool looking keycaps from&#xA0;<a href="https://kbdcraft.store/products/keycap-dss?ref=calvins.pizza" rel="noopener nofollow">KBDCraft</a></p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-20.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1362" height="1372" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-20.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-20.png 1000w, https://calvins.pizza/content/images/2025/02/image-20.png 1362w" sizes="(min-width: 720px) 720px"></figure><p>Once they arrived, I started getting a rough idea of how I wanted the keys to be laid out for a single-hand ergo macropad</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-21.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-21.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-21.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-21.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-21.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>and then modeling a &quot;plate&quot; in blender to print and test the layout on</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/macropad_init_blender_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/macropad_init_blender.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/macropad_init_blender_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:12</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-22.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-22.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-22.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-22.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-22.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>once I was happy with the placement on the test plate, I modeled the rest of the &quot;case&quot; for the keyboard, keeping it very simple and low profile. The bottom of the case would attach which several magnets around the edges of the inside of the top.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-23.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1852" height="1194" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-23.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-23.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-23.png 1600w, https://calvins.pizza/content/images/2025/02/image-23.png 1852w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-24.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1662" height="1238" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-24.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-24.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-24.png 1600w, https://calvins.pizza/content/images/2025/02/image-24.png 1662w" sizes="(min-width: 720px) 720px"></figure><p>on the underside of the case I also added some extra rails for rigidity and some negative space to glue the microcontroller in place.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-25.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-25.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-25.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-25.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-25.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>the switches themselves also ended up in little wells on the top so that the keycaps would sit in a way that would hide the switch bodies</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-26.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-26.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-26.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-26.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-26.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>Then I added the magnets, soldered up the switches to the controller, and made some choices on cap colors to wrap it up</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/macropad_showoff_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/macropad_showoff.mp4" poster="https://img.spacergif.org/v1/720x1280/0a/spacer.png" width="720" height="1280" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/macropad_showoff_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:15</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><h2 id="mounting-everything">Mounting everything</h2><p>This is the thing that is probably most subject to change but mounting these so they weren&apos;t just sitting on top of my desks was important &#x2013; they sit kind of tall so if I did that I feel like it would be like riding one of these motorcycles (no thanks).</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-27.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="1200" height="1200" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-27.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-27.png 1000w, https://calvins.pizza/content/images/2025/02/image-27.png 1200w" sizes="(min-width: 720px) 720px"></figure><p>An obvious choice was a VESA mount, especially since I have an extra monitor arm lying around at the moment.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-28.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-28.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-28.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-28.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-28.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>Unfortunately the best way to mount the arm was &quot;upside down&quot; which is tricky since it wants to spring up against something as heavy as a computer monitor. It works, though, and I can leave it attached to my desk at all time since it swings in from the outside, it actually tucks away nicely!</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230428_203159092_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230428_203159092.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230428_203159092_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:11</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>But I also couldn&apos;t just leave the stick gimbal exposed and the microcontroller dangling by wires that were going to be moving back and forth a lot... so I had to get back to blender to model an enclosure that would house the gimbal and a hold a microcontroller rigged up with a ribbon connector</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/final_stick_mount_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/final_stick_mount.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/final_stick_mount_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:08</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>once that was all re-housed and re-wired to the controller I could put it back on the VESA</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-29.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-29.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-29.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-29.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-29.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>For the throttle for now I just tossed it on an old G5 tower (I have so many of these lol) and just slide it out as needed.</p><figure class="kg-card kg-video-card kg-width-regular" data-kg-thumbnail="https://calvins.pizza/content/media/2025/02/PXL_20230508_153702344.LS_thumb.jpg" data-kg-custom-thumbnail>
            <div class="kg-video-container">
                <video src="https://calvins.pizza/content/media/2025/02/PXL_20230508_153702344.LS.mp4" poster="https://img.spacergif.org/v1/1080x1440/0a/spacer.png" width="1080" height="1440" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/media/2025/02/PXL_20230508_153702344.LS_thumb.jpg&apos;) 50% 50% / cover no-repeat;"></video>
                <div class="kg-video-overlay">
                    <button class="kg-video-large-play-icon" aria-label="Play video">
                        <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                            <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                        </svg>
                    </button>
                </div>
                <div class="kg-video-player-container">
                    <div class="kg-video-player">
                        <button class="kg-video-play-icon" aria-label="Play video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-pause-icon kg-video-hide" aria-label="Pause video">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                                <rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/>
                            </svg>
                        </button>
                        <span class="kg-video-current-time">0:00</span>
                        <div class="kg-video-time">
                            /<span class="kg-video-duration">0:05</span>
                        </div>
                        <input type="range" class="kg-video-seek-slider" max="100" value="0">
                        <button class="kg-video-playback-rate" aria-label="Adjust playback speed">1&#xD7;</button>
                        <button class="kg-video-unmute-icon" aria-label="Unmute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/>
                            </svg>
                        </button>
                        <button class="kg-video-mute-icon kg-video-hide" aria-label="Mute">
                            <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24">
                                <path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/>
                            </svg>
                        </button>
                        <input type="range" class="kg-video-volume-slider" max="100" value="100">
                    </div>
                </div>
            </div>
            
        </figure><p>Then I just tossed the macropad on the laptop stand I use when this desk is for actual work and that was that! It took a bit to map all the controls in Elite but it is&#xA0;<em>extremely</em>&#xA0;fun and I&apos;m surprised in the end how well it all worked!</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2025/02/image-30.png" class="kg-image" alt="3D printing a HOTAS" loading="lazy" width="2000" height="1506" srcset="https://calvins.pizza/content/images/size/w600/2025/02/image-30.png 600w, https://calvins.pizza/content/images/size/w1000/2025/02/image-30.png 1000w, https://calvins.pizza/content/images/size/w1600/2025/02/image-30.png 1600w, https://calvins.pizza/content/images/size/w2400/2025/02/image-30.png 2400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[New Music: Princess Barbara]]></title><description><![CDATA[new Princess Barbara single --
Frend // Return to Amender --
out now!]]></description><link>https://calvins.pizza/new-music-princess-barbara/</link><guid isPermaLink="false">66c7da26454dd8033dd657e4</guid><category><![CDATA[music]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Fri, 23 Aug 2024 13:45:29 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2024/08/Scan_20240611-crop-4-.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2024/08/Scan_20240611-crop-4-.jpg" alt="New Music: Princess Barbara"><p>Listen: <a href="https://princessbarbara.bandcamp.com/album/frend-return-to-amender?ref=calvins.pizza" rel="noreferrer">Bandcamp</a>  <a href="https://music.youtube.com/playlist?list=OLAK5uy_ntN-O9GOLVaRdBfwVCCiCjaJrkRN7gwG0&amp;si=MoRN-Lc3NyYIbFzg&amp;ref=calvins.pizza" rel="noreferrer">YouTube Music</a>  <a href="https://open.spotify.com/album/0n5DHm9t3Ztz07xYeOHpy9?ref=calvins.pizza" rel="noreferrer">Spotify</a></p><p>I&apos;ve been trying and failing for so long to commit myself to releasing some solo songs &#x2013; but today&apos;s the day!</p><p>It&apos;s a small release &#x2013; a 2 sided-single &#x2013; but I&apos;m really excited about it :]</p><p>While <a href="https://calvins.pizza/tag/music/pb/" rel="noreferrer">Princess Barbara</a> used to be a collaboration between <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> and I, it&apos;s currently moving forward as a solo project and I&apos;m proud for this to be the first step in that journey.</p><p>Much of the instrumentation and song writing for this project used to be heavily based around patches created in <a href="https://www.greenoak.com/crystal/about.html?ref=calvins.pizza" rel="noreferrer">Crystal SoftSynth</a>. I used to sit for hours tweaking sounds in that VST or more often rolling the dice on the breed feature:</p><blockquote><br>Patch breeding enables you to create new patches which are combinations of existing patches [...] Select a father patch and a mother patch. Optionally select an amount of mutation, which will introduce a degree of randomness which is not directly derived from either the father or mother. Then press the &quot;Breed&quot; button to create a new patch. (Caution: you can sometimes get unpleasant sounds, so be ready to press Breed again [...]).<br>- <a href="https://www.greenoak.com/crystal/userguide.html?ref=calvins.pizza" rel="noreferrer">Crystal user guide</a></blockquote><p>But I&apos;ve gotten really into hardware synthesizers lately so this single is another kind of first step &#x2013; the shift from Princess Barbara being a band with a limitless instrumentation palette to one limited by the physical instruments I have here at the &quot;studio.&quot; Gone are the MIDI horns and the CPU-melting VSTs and the decision paralysis that comes with that &#x2013; I want to finish more songs now.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/08/PXL_20240823_010123762.jpg" class="kg-image" alt="New Music: Princess Barbara" loading="lazy" width="2000" height="1506" srcset="https://calvins.pizza/content/images/size/w600/2024/08/PXL_20240823_010123762.jpg 600w, https://calvins.pizza/content/images/size/w1000/2024/08/PXL_20240823_010123762.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2024/08/PXL_20240823_010123762.jpg 1600w, https://calvins.pizza/content/images/2024/08/PXL_20240823_010123762.jpg 2000w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">the recording setup</span></figcaption></figure><p>Side A of the single, <strong>Frend</strong>, follow this new &quot;rule&quot; almost entirely &#x2013; I do think there&apos;s one computer synth in there technically.</p><p>Side B, <strong>Return to Amender</strong>, is actually a resurrection of an old sketch done when I was still writing with Pat. That song used to have a ton of Crystal sounds in it and an entirely different vibe and chorus that all got removed. I kept the first vocal melody and Pat&apos;s drum parts that went along with that but re-wrote everything around it, gave the song a new chorus, and buttoned it up. I always really regretted that we never finished this one and I kinda wish I knew what it would have sounded like if we had... but all that considered I&apos;m happy with how it ended up.</p><p>There is a spoken work portion of <strong>Return to Amender</strong> &#x2013; it&apos;s from the speedrunner <strong>tomatoanus</strong> who explains how other runners beat games on youtube. In particular, this sample is edited from the explanation for <a href="How speedrunners beat Tony Hawk&#x2019;s Underground in 32 minutes (SPEEDRUN EXPLAINED - Any%)" rel="noreferrer">How Speedrunners Beat Tony Hawk&apos;s Underground in 32 minutes</a>, but he actually takes a break in all of these videos for this sentiment. There have been a lot of really down times in my life where I was watching his videos in the background and I heard this shit just when I needed it. It fit for the song for me, so it&apos;s there, just wanted to call it out.</p><p>For the cover art I reached out to an old pal I met working in software consulting, <a href="https://prybar.art/?ref=calvins.pizza" rel="noreferrer">Alex Baratta</a>. I follow him on Instagram and noticed he started experimenting with linocut around the time I was wrapping up the writing for the two songs. I am a <em>sucker </em>for most any kind of print and I really liked his style &#x2013; so we agreed to collab! Just as I remembered Alex was wonderful to work with; he immediately had an idea of what he wanted to do and sent a ton of scans for me to pick from before sending my favorites in the mail. I think it turned out _perfect_:</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/08/Scan_20240611-crop-4--1.jpg" class="kg-image" alt="New Music: Princess Barbara" loading="lazy" width="1400" height="1472" srcset="https://calvins.pizza/content/images/size/w600/2024/08/Scan_20240611-crop-4--1.jpg 600w, https://calvins.pizza/content/images/size/w1000/2024/08/Scan_20240611-crop-4--1.jpg 1000w, https://calvins.pizza/content/images/2024/08/Scan_20240611-crop-4--1.jpg 1400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Princess Barbara]]></title><description><![CDATA[<p>Princess Barbara began after I graduated college and mostly exists on the computer; I never had plans to get a band together or play live, but I was moving away from home so <a href="https://calvins.pizza/tag/music/ttd" rel="noreferrer">Think Twice, Dublin</a> was going on hiatus and I still wanted to write music. While much of</p>]]></description><link>https://calvins.pizza/princess-barbara/</link><guid isPermaLink="false">66c211c9454dd8033dd65701</guid><category><![CDATA[hidden]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 18 Aug 2024 17:33:02 GMT</pubDate><content:encoded><![CDATA[<p>Princess Barbara began after I graduated college and mostly exists on the computer; I never had plans to get a band together or play live, but I was moving away from home so <a href="https://calvins.pizza/tag/music/ttd" rel="noreferrer">Think Twice, Dublin</a> was going on hiatus and I still wanted to write music. While much of the writing was shared with <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a>, especially early on, it has slowly and finally become a solo effort.</p><p>When starting the project I wanted to experiment with more electronic and synth sounds without too much limitation....I definitely remember being heavily inspired by <a href="https://en.wikipedia.org/wiki/The_Age_of_Adz?ref=calvins.pizza" rel="noreferrer">Age of Adz</a> this time of my life; a lot of the early Princess Barbara tracks have a lot of (digital) horns on them.</p><p>More recently the music has gotten more instrumentally focused and predictably melancholic. While the instrumentation used to be heavily influenced by complex digital virtual instruments, Princess Barbara now sticks to physical hardware synthesizers and bass/guitar, while the drums are patch-programmed on a eurorack drum machine and adjusted later for fills and variation.</p><p>While releases are slow, the project is active, feel free to drop a follow on your preferred streaming platform or download for free on bandcamp.</p>]]></content:encoded></item><item><title><![CDATA[Blød Maud]]></title><description><![CDATA[<p>Bl&#xF8;d Maud started after I moved to Pittsburgh in 2013.</p><p>Emily Crossen had also moved to Pittsburgh from State College a year or two before, but we were not close beforehand.</p><p>It was my girlfriend at the time Shana, a long time friend of Emily, that discovered Emily&</p>]]></description><link>https://calvins.pizza/blod-maud/</link><guid isPermaLink="false">66c21b62454dd8033dd6573c</guid><category><![CDATA[hidden]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 18 Aug 2024 17:32:51 GMT</pubDate><content:encoded><![CDATA[<p>Bl&#xF8;d Maud started after I moved to Pittsburgh in 2013.</p><p>Emily Crossen had also moved to Pittsburgh from State College a year or two before, but we were not close beforehand.</p><p>It was my girlfriend at the time Shana, a long time friend of Emily, that discovered Emily&apos;s &quot;secret&quot; soundcloud page. It turns out that without ever really telling anyone that close to her, Emily had been writing and recording songs as &quot;Bl&#xF8;d Maud&quot; for some time, and that shit was good.</p><p>Shana was always neck-deep in whatever music scene she was around so she immediately found a show for Emily to play to try and show off her writing:</p><blockquote>&#x201C;I didn&#x2019;t want to play by myself,&#x201D; she says. &#x201C;So I was like, &#x2018;I gotta get some dudes.&#x2019;&#x201D;<br>- <a href="https://www.pghcitypaper.com/arts-entertainment/blod-maud-belies-its-own-apparent-nonchalance-with-a-haunting-hook-filled-ep-3815491?ref=calvins.pizza" rel="noreferrer">Margaret Welsh, quoting Emily Crossen, PGH City Paper</a></blockquote><p>Bl&#xF8;d Maud only lasted an album and 2 EPs as Emily moved to Philly, <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> got very serious about his solo stuff, and our 2nd bass player Eli got into economics and math, the band just kind of drifted as the writing slowed down.</p><p>I will always be very proud of this band &#x2013; we had so much fun writing and hanging out together and brought a fun energy to the stage. Selfishly it was also fun to not have any &quot;song writing&quot; responsibilities but to mostly get to write lead guitar melodies on top of Emily&apos;s already hypnotic tracks.</p><p>If any of the bands I was in ever had a shot at larger appeal, this was probably it. Sometimes I wish we could have stuck to it and worked a little harder, tried touring...but maybe that would have not been Bl&#xF8;d Maud anyway.</p><p>I still keep in touch with Emily frequently, though I don&apos;t visit often enough. Same with Pat. Eli and I had a long-running &quot;joke&quot; (honestly I don&apos;t think he liked me enough to be good friends with me) about never having each other&apos;s phone numbers but I think he&apos;s doing well teaching somewhere. Rob, our first bass player, sometimes reaches out as well &#x2013; that dude rules and I miss him.</p><p>Shana tragically passed in 2016 well after effectively forming the band, she is missed and remembered so often, but especially when I think about Bl&#xF8;d Maud.</p>]]></content:encoded></item><item><title><![CDATA[Crybaby Apprentice]]></title><description><![CDATA[<p>Crybaby Apprentice began, like many things, at the beginning of the Covid-19 pandemic around march 2020.</p><p>While it started as a larger group of old pals trying to collab on some music together, the band quickly reduced to me and my friend Andrew (of <a href="https://calvins.pizza/tag/music/ttd" rel="noreferrer">Think Twice, Dublin</a>). </p><p><a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> (also</p>]]></description><link>https://calvins.pizza/crybaby-apprentice/</link><guid isPermaLink="false">66c21f8d454dd8033dd6577c</guid><category><![CDATA[hidden]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 18 Aug 2024 17:32:42 GMT</pubDate><content:encoded><![CDATA[<p>Crybaby Apprentice began, like many things, at the beginning of the Covid-19 pandemic around march 2020.</p><p>While it started as a larger group of old pals trying to collab on some music together, the band quickly reduced to me and my friend Andrew (of <a href="https://calvins.pizza/tag/music/ttd" rel="noreferrer">Think Twice, Dublin</a>). </p><p><a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> (also of TT,D) often contributed drum tracks once song structures were mostly finished. </p><p>Historically Andrew and I had been pretty into writing repetitive, droney music and this was the time to try something different. Andrew often referred to it as &quot;horizontal&quot; song writing &#x2013; the idea was basically to oppose our previous patterns by focusing on long phrases and chord progressions while limiting any obvious repetition.</p><p>We were lucky that our first single got picked up and added to a tape compilation, <a href="https://infinitoaudio.bandcamp.com/album/stargate-02?ref=calvins.pizza" rel="noreferrer">STARGATE 02 by Infinito Audio Network</a>. That label asked us if we had more so we took our time writing a themed EP around the ideas of pulp horror from the perspective of a villain. I don&apos;t know if we took too long or if they just didn&apos;t like the EP over at Infinito, but we eventually released the EP <a href="https://crybabyapprentice.bandcamp.com/album/pathwork?ref=calvins.pizza" rel="noreferrer">Pathwork</a> on our own.</p><p>Still active, Crybaby Apprentice is a delight of complex collaboration and experimental challenges. I&apos;m looking forward to writing more with Andrew under this project</p>]]></content:encoded></item><item><title><![CDATA[Think Twice, Dublin]]></title><description><![CDATA[<p>Think Twice, Dublin was an experimental guitar pop band consisting of myself, <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> (on drums and vocals), and Andrew Huffard (of <a href="https://calvins.pizza/tag/music/cba" rel="noreferrer">Crybaby Apprentice</a>).</p><p>We started writing together just to have a reason to play in Battle of the Bands our senior year of high school, our previous band had</p>]]></description><link>https://calvins.pizza/think-twice-dublin/</link><guid isPermaLink="false">66c22a43454dd8033dd657ac</guid><category><![CDATA[hidden]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 18 Aug 2024 17:32:33 GMT</pubDate><content:encoded><![CDATA[<p>Think Twice, Dublin was an experimental guitar pop band consisting of myself, <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> (on drums and vocals), and Andrew Huffard (of <a href="https://calvins.pizza/tag/music/cba" rel="noreferrer">Crybaby Apprentice</a>).</p><p>We started writing together just to have a reason to play in Battle of the Bands our senior year of high school, our previous band had sort of dissolved. Initially we took heavy influence from ultra-repetitive kraut type music, writing <a href="https://thinktwicedublin.bandcamp.com/track/stapled-skies-2?ref=calvins.pizza" rel="noreferrer">Stapled Skies</a> to perform before we graduated.</p><p>Though college took Andrew briefly to Ohio, he returned after a year or so to our hometown where Pat and I were attending school. This allowed us to re-group and write what may be the music I&apos;m most proud of &#x2013; &quot;The Parent Singles.&quot; </p><p>Thematically The Parent Singles weren&apos;t related at all but there were 3 singles (with A/B sides) and each cover adorned cover photos of one of the member&apos;s parents, so we always called them that. It also makes me think we&apos;re like The Beta Band with &quot;The Three EPs&quot; which is cool, I guess.</p><p>We played around State College for the remainder of our college years, gathering a niche local following for a small amount of time. There were a few times we were lucky to open for some pretty cool acts like <a href="https://en.wikipedia.org/wiki/Cymbals_Eat_Guitars?ref=calvins.pizza" rel="noreferrer">Cymbals Eat Guitars</a> and <a href="https://en.wikipedia.org/wiki/School_of_Seven_Bells?ref=calvins.pizza" rel="noreferrer">School of Seven Bells</a>.</p><p>The loss of this band is a romantic tragedy to me, I&apos;ll always wonder what could have been in some way. But I&apos;m super glad I have the memories and recordings I do have.</p>]]></content:encoded></item><item><title><![CDATA[New Music: Crybaby Apprentice]]></title><description><![CDATA[new Crybaby Apprentice EP Pathwork out now]]></description><link>https://calvins.pizza/new-music-crybaby-apprentice-2/</link><guid isPermaLink="false">66ae23cd454dd8033dd656cd</guid><category><![CDATA[music]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sat, 03 Aug 2024 13:14:09 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2024/08/pw-final.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2024/08/pw-final.jpg" alt="New Music: Crybaby Apprentice"><p>TL;DR: <a href="https://crybabyapprentice.bandcamp.com/album/pathwork?ref=calvins.pizza" rel="noreferrer">listen to EP Pathwork here</a></p><p>During the initial covid isolation, friend Andrew and I started playing around with what we called &quot;horizontal&quot; song writing as an experiment. We released a single I wrote about <a href="https://calvins.pizza/new-music-crybaby-apprentice/" rel="noreferrer">here</a> and it randomly got added to a <a href="https://soundcloud.com/infinitoaudiolabel/sets/vv-aa-stargate-02?ref=calvins.pizza" rel="noreferrer">pretty rad tape compilation</a> for <a href="https://infinitoaudio.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Infinito Audio Network</a>.</p><p>Well, that magazine/label did ask us if we had more music for a solo tape. We did not have more music but decided to get to it, deciding to try and write a thematic EP.</p><p>The theme ended up being something like &quot;spooky love songs&quot; or perhaps &quot;romance with ill intent&quot; and we ended up with 6 tracks we were pretty proud of! Unfortunately we did take a long time to do so &#x2013;  by the time we sent rough mixes to Infinito they either didn&apos;t like what they heard or had moved on and decided they didn&apos;t want to release the tape.</p><p>We did kinda just sit on it for a little bit, wondering if we should try to reach out to other small labels for help on physical copies, distribution, outreach.... but it does seem like that kind of work (sending countless emails) doesn&apos;t excite Andrew or I enough to do it effectively.</p><p>So, finally, <a href="https://crybabyapprentice.bandcamp.com/album/pathwork?ref=calvins.pizza" rel="noreferrer">here it is</a>! The drums were written by friend <a href="https://patcoyle.bandcamp.com/?ref=calvins.pizza" rel="noreferrer">Pat Coyle</a> and the EP was mastered by the ever-kind <a href="https://www.facebook.com/davidklugstudio" rel="noreferrer">David Klug</a></p>]]></content:encoded></item><item><title><![CDATA[Voltage Controlled Video Looper]]></title><description><![CDATA[Designing and building an LZX/Eurorack compatible video clip player and looper]]></description><link>https://calvins.pizza/voltage-controlled-video-looper/</link><guid isPermaLink="false">66536300c644cc67bf056e06</guid><category><![CDATA[dev]]></category><category><![CDATA[projects]]></category><category><![CDATA[synth]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Tue, 06 Feb 2024 15:29:48 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2024/02/PXL_20240202_032412521-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2024/02/PXL_20240202_032412521-1.jpg" alt="Voltage Controlled Video Looper"><p>I have been long putting together an <a href="https://lzxindustries.net/?ref=calvins.pizza">LZX</a> video synth and with the eventual arrival of my <a href="https://lzxindustries.net/products/tbc2?ref=calvins.pizza">TBC2</a> module I finally had a reliable way to send external video into the gear. While I initially had a lot of fun with an old VCR and thrift store VHS finds....well, it turns out having to rewind all those VHS&apos; kinda sucks, hah. Then once they are rewound you have to fast-forward them to the actual content you want to see or at least past all the trailers and FBI warnings.</p><blockquote>want to go straight to the code?<br><a href="https://github.com/CMorooney/clippi?ref=calvins.pizza">check out the repo here</a></blockquote><p>So I decided I wanted to design and build a dedicated video player to be able to loop through smaller chunks of more curated content using a <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/?ref=calvins.pizza">Raspberry Pi 4</a>. My initial sketch looked like this:</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/og_clipplayer_sketch.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1079" height="1328" srcset="https://calvins.pizza/content/images/size/w600/2024/02/og_clipplayer_sketch.png 600w, https://calvins.pizza/content/images/size/w1000/2024/02/og_clipplayer_sketch.png 1000w, https://calvins.pizza/content/images/2024/02/og_clipplayer_sketch.png 1079w" sizes="(min-width: 720px) 720px"></figure><p>The main features I laid out were:</p><!--kg-card-begin: markdown--><ul>
<li>12 Banks of 12 Clips
<ul>
<li>use a 7 segment display to show current Bank &amp; Clip indexes</li>
<li>managed via a local web server/interface</li>
</ul>
</li>
<li>Radial Playhead to show progress of current Clip</li>
<li>6 Buttons
<ul>
<li><strong>Mode:</strong> toggle between random/sequential playing of the current Bank</li>
<li><strong>Prev:</strong> go to previous video in Bank</li>
<li><strong>Play:</strong> toggle play/pause of Clip</li>
<li><strong>Next:</strong> go to next video in Bank</li>
<li><strong>Hold:</strong> loop current Clip indefinitely (toggle)</li>
<li><strong>Shft:</strong> shift button. hold and use Prev/Next to switch Banks</li>
</ul>
</li>
</ul>
<!--kg-card-end: markdown--><p>It all seemed pretty doable from a high-level!</p><p>First thing I did was try and source the components for the &apos;Radial Playhead&apos; and Segmented Displays just to make sure they were something I could find and work with reasonably. Of course, <a href="https://www.adafruit.com/?ref=calvins.pizza">Adafruit</a> had everything I needed, including the libraries and helpful documentation to take out a lot of guess work. I grabbed a <a href="https://www.adafruit.com/product/1643?ref=calvins.pizza">12 pixel Neopixel Ring</a> for the Playhead and a <a href="https://www.adafruit.com/product/879?ref=calvins.pizza">4-Digit 7 Segment Display</a> for the Bank/Clip indicators. I would have preferred 2 2-digit displays as I sketched out, but they only had the 4-digit variety over there and it came included with a &quot;<a href="https://www.adafruit.com/product/877?ref=calvins.pizza">backpack</a>&quot; to handle all the i2c matrix nonsense so it was a no-brainer. Once they all showed up in the mail I started plopping everything down:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/02/sketch_to_breadboard.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1036" height="961" srcset="https://calvins.pizza/content/images/size/w600/2024/02/sketch_to_breadboard.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/sketch_to_breadboard.jpeg 1000w, https://calvins.pizza/content/images/2024/02/sketch_to_breadboard.jpeg 1036w" sizes="(min-width: 720px) 720px"><figcaption>that IC is a 74AHCT125 quad level-shifter that&apos;s needed for the Neopixel Ring (well, one shifter is needed)</figcaption></figure><p>Not bad! I got all the main interface hardware on a breadboard and wired it up to the power and the Raspberry Pi. Which meant I had to get started on the actual software side of the project.</p><p>The first part of the software I went after was creating the web server/interface to manage the Banks and Clips on the machine. I was inspired by how <a href="https://monome.org/docs/norns/?ref=calvins.pizza">norns</a> used a local web interface for its own management and <a href="https://calvins.pizza/building-norns-shield-s/">building a norns</a> was also the last time I used a Raspberry Pi so it easily came to mind. Since I am not really worried about security as this is only accessible through LAN, I went with a simple <a href="https://flask.palletsprojects.com/en/3.0.x/?ref=calvins.pizza">flask</a> app. It did take me a full weekend of working on/off to get all this work done, but I think it has all the features you&apos;d want:</p><!--kg-card-begin: markdown--><ul>
<li>Upload files from the computer accessing the web interface</li>
<li>Download YouTube videos straight to a Bank<br>
- optionally provide start/end timestamps to only download part of the video</li>
<li>Rename Clip</li>
<li>Re-order Clip in Bank</li>
<li>Delete Clip</li>
</ul>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/web_interface_final.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1191" height="760" srcset="https://calvins.pizza/content/images/size/w600/2024/02/web_interface_final.png 600w, https://calvins.pizza/content/images/size/w1000/2024/02/web_interface_final.png 1000w, https://calvins.pizza/content/images/2024/02/web_interface_final.png 1191w" sizes="(min-width: 720px) 720px"></figure><p>Once that was all done, I could move on to sorting out how to actually play and loop content on the Pi.</p><p>After searching around I landed on <a href="http://www.mplayerhq.hu/?ref=calvins.pizza">MPlayer</a> because it seemed to have good documentation and had playlist support which I thought might come in handy as a representation of a Bank.</p><p>It took me a little bit to figure out how to manage MPlayer best from the python script that was my main Clip player application. Sparing boring tales of trial and error I ended up using MPlayer in &quot;<a href="http://www.mplayerhq.hu/DOCS/tech/slave.txt?ref=calvins.pizza#:~:text=The%20%2Dslave%20option%20switches%20on,newline%20(%5Cn)%20from%20stdin.&amp;text=and%20type%20slave%20commands%20into%20the%20console%20window.">Slave Mode</a>.&quot; This mode allowed me to send MPlayer commands via <code>stdin</code>, which is how I would issue the commands to go to the next clip, etc. Combining that with <a href="https://pexpect.readthedocs.io/en/stable/?ref=calvins.pizza">pexpect</a> meant I could spawn a process of MPlayer in &quot;Slave Mode&quot; and issue it commands, then wait for and read responses while still handling button presses in the app code.</p><p>Once I finally was able to upload clips to the device via the web interface and play them with MPlayer, I could actually test the full content loop for the first time:</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2024/02/initial_into_synth.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2024/02/media-thumbnail-ember491.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>Once I had this proof of life, I could write the rest of the code to implement all of the features I lined out above &#x2013; I was lucky to be able to include them all! <a href="https://github.com/CMorooney/clippi/blob/master/app.py?ref=calvins.pizza">The application code can be viewed here</a> if you&apos;re curious to see how I accomplished that.</p><p>Back to the circuit! I had all the buttons wired up and their respective functions working in the software, but I still hadn&apos;t made this thing LZX/Eurorack compatible, i.e I had yet to add voltage control.</p><p>I quickly made a circuit for a voltage control input with my best attempt at negative voltage protection, over-voltage protection, proper impedance, and amplification. </p><p>The protections were to stop any damage occurring to components down line in the circuit or any GPIO pins on the Pi itself if any incoming voltage was outside a safe range. I added an amplifier to the end of this part of the circuit so that voltage as low as ~1v would be scaled up to something that the Pi GPIO would detect (&gt;= ~3.3v). LZX format synths usually work in the 0-1v range which is what motivated this addition.</p><p>Just after the amplifier I added a single signal diode that will share a Cathode with a diode trailing the Button paired with the voltage input. This should create a passive logical &apos;OR&apos; between the voltage controlled input and the button so that if they are activated at the same time the voltage doesn&apos;t stack. I could/should have added a high value resistor to ground at this same node but I think the internal pull down at the GPIO should suffice. </p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/input_circuit.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1073" height="1005" srcset="https://calvins.pizza/content/images/size/w600/2024/02/input_circuit.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/input_circuit.jpeg 1000w, https://calvins.pizza/content/images/2024/02/input_circuit.jpeg 1073w" sizes="(min-width: 720px) 720px"></figure><p>It should probably be noted that I&apos;m a total novice when it comes to analog circuit design and there are probably better and cheaper ways to accomplish my goals in general, and especially in this case.</p><p>That voltage input was the last part of the circuit I need to move on to designing the PCBs! There was going to be one for the control board (where the buttons and voltage input circuits would be) and a &quot;hat&quot; for the Pi connected by a ribbon cable. I decided to use <a href="https://www.kicad.org/?ref=calvins.pizza">KiCad</a> so I first had to convert my breadboard into a schematic with actual part footprints that could be brought into the PCB designer.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.23.00-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="525" height="509"><figcaption>single voltage input schematic for control board and ribbon connector</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.24.19-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="735" height="952" srcset="https://calvins.pizza/content/images/size/w600/2024/02/Screenshot-2024-02-06-at-10.24.19-AM.png 600w, https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.24.19-AM.png 735w" sizes="(min-width: 720px) 720px"><figcaption>schematic for the Pi hat</figcaption></figure><p>I did replace the quad level-shifter I had on the breadboard with a more discreet single level-shifter in the final schematic since I only needed the one.</p><p>Once that was done I could do the actual PCB layout and get them manufactured. This took a week or so per board so I had to do a little waiting.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.25.09-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="670" height="489" srcset="https://calvins.pizza/content/images/size/w600/2024/02/Screenshot-2024-02-06-at-10.25.09-AM.png 600w, https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.25.09-AM.png 670w"><figcaption>PCB layout for the control board</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.24.49-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="805" height="698" srcset="https://calvins.pizza/content/images/size/w600/2024/02/Screenshot-2024-02-06-at-10.24.49-AM.png 600w, https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.24.49-AM.png 805w" sizes="(min-width: 720px) 720px"><figcaption>PCB layout for the Pi hat</figcaption></figure><p>But they did arrive!</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2024/02/first_pcb_delivery.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2024/02/media-thumbnail-ember592.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>The first thing I did was solder up a control board and test it against the breadboard version of the Pi hat just to make sure that was working properly. I also did create a ribbon cable helper for the breadboard to help.</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2024/02/ctl_board_test_harness_5.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="1080" height="1920" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2024/02/media-thumbnail-ember654.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>Now with all the circuitry and software pieces complete, I had to finally bite the bullet on making some kind of enclosure. I am novice enough at analogue circuit design, but this was an even larger uphill battle for me as I&apos;ve never had the attention span to <em>really</em> learn <a href="https://www.blender.org/?ref=calvins.pizza">Blender</a> past the very basics, but I headed on as the plan was to 3D print the enclosure.</p><p>I started by making sure I could get a good fit for the pi and the control board, even that took more than a couple tries for me</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/tigher_print.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1078" height="1193" srcset="https://calvins.pizza/content/images/size/w600/2024/02/tigher_print.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/tigher_print.jpeg 1000w, https://calvins.pizza/content/images/2024/02/tigher_print.jpeg 1078w" sizes="(min-width: 720px) 720px"></figure><p>After much trial and error I eventually did end up with <em>some</em> kind of enclosure. I wasn&apos;t really that happy with it but I got it to the point where I could at least test fit everything. It was just so blocky and tall.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/enclosure_v1_complete.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1077" height="766" srcset="https://calvins.pizza/content/images/size/w600/2024/02/enclosure_v1_complete.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/enclosure_v1_complete.jpeg 1000w, https://calvins.pizza/content/images/2024/02/enclosure_v1_complete.jpeg 1077w" sizes="(min-width: 720px) 720px"></figure><p>A big part of me didn&apos;t want to, but I took it back to the drawing board at this point. I really felt that after stumbling through Blender for a week to get here and picking up some knowledge I could make something better in a shorter amount of time.</p><p>The first thing I did was tilt the control board in Blender to try and get some vertical space back, I moved it up a bit as well.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/enclosure_v2.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1078" height="559" srcset="https://calvins.pizza/content/images/size/w600/2024/02/enclosure_v2.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/enclosure_v2.jpeg 1000w, https://calvins.pizza/content/images/2024/02/enclosure_v2.jpeg 1078w" sizes="(min-width: 720px) 720px"></figure><p>Then I brought in reference models for the Radial Playhead and the 7 Segment display and tried get a good position for those.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.04.37-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="757" height="380" srcset="https://calvins.pizza/content/images/size/w600/2024/02/Screenshot-2024-02-06-at-10.04.37-AM.png 600w, https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.04.37-AM.png 757w" sizes="(min-width: 720px) 720px"></figure><p>From there I just shaped a Plane to the profile of the new layout of all the components. After extruding that to the proper width I could start to make it an actual box, i.e removing inner volume and separating top &amp; bottom. Then there was the busy work of punching all the IO and thread holes... As I predicted it was not long before I had something I was <em>much</em> happier with.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.08.09-AM.png" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="791" height="652" srcset="https://calvins.pizza/content/images/size/w600/2024/02/Screenshot-2024-02-06-at-10.08.09-AM.png 600w, https://calvins.pizza/content/images/2024/02/Screenshot-2024-02-06-at-10.08.09-AM.png 791w" sizes="(min-width: 720px) 720px"></figure><p>Some lightly rounded corners went a very long way but I think the overall shape is much more pleasing and interesting now as well! It also come out pretty decent in the print!</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/enclosure_v2_loose_fit.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="826" height="1463" srcset="https://calvins.pizza/content/images/size/w600/2024/02/enclosure_v2_loose_fit.jpeg 600w, https://calvins.pizza/content/images/2024/02/enclosure_v2_loose_fit.jpeg 826w" sizes="(min-width: 720px) 720px"></figure><p><em>Now</em> that I had an enclosure I was more proud of I could move on to adding the threads and wiring everything up. Most of this was pretty simple...the one thing that I would like to change in another iteration of this enclosure is the &apos;captive&apos; Radial playhead, though. At the moment you have to solder the Playead wires after they are already routed and connected on one end, just not ideal.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/enclosure_v2_wiring.jpeg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="1073" height="994" srcset="https://calvins.pizza/content/images/size/w600/2024/02/enclosure_v2_wiring.jpeg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/enclosure_v2_wiring.jpeg 1000w, https://calvins.pizza/content/images/2024/02/enclosure_v2_wiring.jpeg 1073w" sizes="(min-width: 720px) 720px"></figure><p>After wiring everything up I could finally turn it back on! Looking prettttyyy good.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2024/02/PXL_20240205_191748016.jpg" class="kg-image" alt="Voltage Controlled Video Looper" loading="lazy" width="2000" height="1805" srcset="https://calvins.pizza/content/images/size/w600/2024/02/PXL_20240205_191748016.jpg 600w, https://calvins.pizza/content/images/size/w1000/2024/02/PXL_20240205_191748016.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2024/02/PXL_20240205_191748016.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2024/02/PXL_20240205_191748016.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>This was my very first time taking a circuit/gizmo idea from literal sketch to working &quot;product.&quot; I&apos;ve never completed a real schematic before in proper software and definitely hadn&apos;t designed and gotten my own PCBs milled. The whole Blender process was such a big hill to climb in its own right.</p><p>I used to look at schematics and PCBs with total awe, thinking there would never be a way I could understand let alone make something like that. This feels incredibly cool.</p>]]></content:encoded></item><item><title><![CDATA[Obsidian Game Search 0.2.0: Steam Sync]]></title><description><![CDATA[Steam Sync added to Game Search Obsidian Plugin!]]></description><link>https://calvins.pizza/obsidian-game-search-0-2-0-steam-sync/</link><guid isPermaLink="false">66536300c644cc67bf056e05</guid><category><![CDATA[dev]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Thu, 25 Jan 2024 15:01:54 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2024/01/Screenshot-2024-01-25-at-9.27.04-AM.png" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2024/01/Screenshot-2024-01-25-at-9.27.04-AM.png" alt="Obsidian Game Search 0.2.0: Steam Sync"><p>I&apos;m still using <a href="https://obsidian.md/?ref=calvins.pizza">Obsidian</a> and I&apos;m still using that &quot;Good Reads for Games&quot; plugin <a href="https://calvins.pizza/goodreads-for-games-with-obsidan-md/">I wrote about a bit ago</a>.</p><p>Since then I&apos;ve built a nice gaming PC for myself and lot of my gaming has been more split between more platforms (previously I was almost exclusively playing switch games with the occasional PS4 title). I of course also became a much heavier <a href="https://store.steampowered.com/?ref=calvins.pizza">Steam</a> user which has a fantastic Wishlist feature that most people use pretty frequently.</p><p>This presented a new redundancy problem for me &#x2013; I was hearing about games and adding them to my Steam Wishlist....well then I&apos;d have to remember to add them to my backlog in my Obsidian Vault. <strong>THEN</strong> when I got a notification that a game on my Wishlist was on sale I had to remember to move my vault file from my internal &quot;wishlist&quot; to &quot;owned backlog&quot; upon purchase. This was super annoying and no doubt games get lost in the shuffle.</p><p>So I set out to add Steam integration to my <a href="https://github.com/CMorooney/obsidian-game-search-plugin?ref=calvins.pizza">Game Search Plugin</a>. And I did! Introducing <code>0.2.0</code> of Game Search, live now.</p><p>While the new feature does require you to get a Steam API key and do a few more set up steps, it has at the very least solved my problem of having two sets of &quot;backlogs&quot; to maintain. (One easy thing to miss is that your Wishlist on Steam must be set to <code>Public</code> to be queryable!)</p><p>After entering your Steam credentials in the plugin settings you can invoke <code>Sync Steam</code> as a command. It&apos;s important to note that this can take some time, especially for larger libraries, since the plugin has to iterate over each game in your Steam Library and Wishlist and try to match it with a game in your vault OR from the RAWG API, then either create a new file (requiring another RAWG Api call) or update the matched one with the proper metadata.</p><p>By default all the <code>Steam Sync</code> actually does is ensure that there is a file for all the games in your Library and Wishlist and that they have a <code>steamId</code> metadata property.</p><p>In the Settings for the Game Search Plugin there are two text fields, <code>metadata for owned Steam games</code> and <code>metadata for wishlisted Steam games</code>. Use these fields to inject metadata key/value pairs into wishlist and library games upon sync.</p><p>For example, my <code>metadata for owned Steam games</code> looks like this:</p><!--kg-card-begin: markdown--><pre><code>owned: true
owned_platform: steam
</code></pre>
<!--kg-card-end: markdown--><p>And my <code>metadata for wishlisted Steam games</code> looks like this:</p><!--kg-card-begin: markdown--><pre><code>owned: false
status: backlog
</code></pre>
<!--kg-card-end: markdown--><p>So now I can differentiate between wishlisted and owned games through the metadata of the game files!</p><p>Right now the injected metadata for Steam games does not support templating or any kind of variable injecting and instead relies on hard-coded values like the above examples but I could see adding on some kind of templating feature in the future if it&apos;s requested enough.</p><p>This was all I needed to solve my problem! Hopefully it helps others, though while it is working on my machine please feel free to <a href="https://github.com/CMorooney/obsidian-game-search-plugin/issues/new/choose?ref=calvins.pizza">open an issue</a> on Github for any bugs or feature requests!</p><h2 id="one-more-thing">One more thing...</h2><p>There is another thing that&apos;s been bothering me about my Game Search plugin.</p><p>There is a feature buried in the Settings page to <code>Regenerate</code> all of your game files based on your <a href="https://github.com/SilentVoid13/Templater?ref=calvins.pizza">Template</a> file. The idea behind this is that you might change how you want your files to be generated but you already have many many files built on an old template.</p><p>Until now, using this feature would <strong>completely</strong> regenerate your notes so you would lose <strong>any and all</strong> non-templated content to the process.</p><p>This bothered me as a fan of &quot;keepsake&quot; games &#x2013; I actually do take notes in some of these game files to remember tasks or secrets, or of course to solve puzzles. Regenerating all the files to a template would lose all of my important, actual game notes.<br><br>So now the <code>Regenerate</code> button works differently &#x2013; the only portion of your existing game files that is regenerated is the metadata, the rest is left alone. I have a hunch this fits better with how folks use the plugin but I&apos;m eager to hear if I&apos;m way off base.</p><p>One important piece to this is that while the previous metadata for a file gets blown away during Regeneration, <code>steamId</code> and any custom metadata provided via <code>metadata for owned Steam games</code> or <code>metadata for wishlisted Steam games</code> will be copied over to the newly regenerated metadata for preservation.</p>]]></content:encoded></item><item><title><![CDATA[Arboretum SwiftUI/TCA app]]></title><description><![CDATA[quick sample app using The Composable Architecture, Swift, and Realm]]></description><link>https://calvins.pizza/arboretum-swiftui-tca-ios-app/</link><guid isPermaLink="false">66536300c644cc67bf056e04</guid><category><![CDATA[dev]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Sun, 31 Dec 2023 19:01:19 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2023/12/idk.png" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2023/12/idk.png" alt="Arboretum SwiftUI/TCA app"><p>It&apos;s been a couple years since I got to work professionally on Swift applications, and I have to say, I miss it! The language has always been super attractive to me as someone who prefers to more defensive and opinionated environments.... yeah, I kinda like thinking about memory!</p><p>So I&apos;m looking to get back into the Swift game, but the language has released a lot of updates since I last used it professionally on the <a href="https://apps.apple.com/us/app/giant-eagle/id1465897036?ref=calvins.pizza">GiantEagle</a> grocery app (oddly under two different companies, <a href="https://www.gianteagle.com/?ref=calvins.pizza">Giant Eagle</a> themselves and Hatched Labs. Not worth getting into here but basically the former bought the latter and moved all their mobile dev over to them).</p><p>I&apos;ve had to watch from the sidelines (&amp; with little test projects to keep up) as Swift finally got async/await syntax among so many other features. Even SwiftUI finally became more viable as a framework, something we only got to experiment with at GiantEagle/Hatched (our application was built on UIKit and Auto Layout).</p><p>Then there was <a href="https://github.com/pointfreeco/swift-composable-architecture?ref=calvins.pizza">The Composable Architecture</a>! I had been hearing a lot of rumbles about this redux-elm-like, swift-first framework and I wanted to try it out since we were using <a href="https://github.com/ReactiveX/RxSwift?ref=calvins.pizza">RxSwift</a> at GE/Hatched.</p><p>So over the recent holiday I set off to make a tiny complete application with SwiftUI and The Composable Architecture, using <a href="https://realm.io/realm-swift/?ref=calvins.pizza">Realm</a> for local data storage. The choice to use Realm was another attempt to broaden my experience &#x2013; I haven&apos;t used it in so many years and definitely not in a uni-directional Swift application. In hindsight I wish I could&apos;ve spent more time understanding how I could <em>cleanly</em> fit Realm in a bit better, and that&apos;s something I definitely look to improve after this initial work.</p><p>I grew up in State College PA, so I have always been a big fan of <a href="https://arboretum.psu.edu/?ref=calvins.pizza">The Arboretum at PSU</a>. In an often over-crowded campus this is a beautiful reprieve and the staff works really hard to make sure it&apos;s always alive and changing. In the last few years they opened their <a href="https://www.psu.edu/news/campus-life/story/pollinator-and-bird-garden-opens-arboretum-penn-state/?ref=calvins.pizza">Pollinator Garden</a> which was an insanely large and incredible expansion of an already inspiring space. It&apos;s one of the last great human-managed things in State College to check out &#x2013; if you get a chance you must go.</p><p>The Arboretum also served as a great subject for this little micro-app project. The staff at The Arboretum keeps meticulous amounts of data on their collections and have a nice <a href="https://datacommons.maps.arcgis.com/apps/webappviewer/index.html?id=88d9267530dc48db8635703130bb084e&amp;ref=calvins.pizza">interactive ArcGIS/ESRI map</a> with all the plants mapped out on their property. Opening that map and looking at the network tab of your browser will expose the actual requests for the map data, here&apos;s the url of the request I ended up using:</p><!--kg-card-begin: markdown--><p><code>https://apps.pasda.psu.edu/arcgis/rest/services/PlantFinder_Combined_Accessions_01212019/FeatureServer/0/query?f=json&amp;returnGeometry=true&amp;spatialRel=esriSpatialRelIntersects&amp;geometry=%7B%22xmin%22%3A-8668570.5047493%2C%22ymin%22%3A4983694.245496575%2C%22xmax%22%3A-8667959.008523071%2C%22ymax%22%3A4984305.741722804%2C%22spatialReference%22%3A%7B%22wkid%22%3A102100%7D%7D&amp;geometryType=esriGeometryEnvelope&amp;inSR=102100&amp;outFields=*&amp;outSR=4326&amp;resultType=til</code></p>
<!--kg-card-end: markdown--><p>Actually, that request is slightly modified. The value for the query param `outSR` has been changed from its original value to `4326`, which signifies that we want our returned data to be projected into Web Mercator space (<a href="https://github.com/Esri/projection-engine-db-doc/blob/main/json/pe_list_geogcs.json?ref=calvins.pizza#L4538">id found here</a>). The map as it exists on the web is projected in NAD 1983 space, which makes sense since that projection seems to be focused on the continental United States and the Arboretum map has no need for accuracy outside of that.</p><p>But, alas, iOS maps (like many other tools) project in Web Mercator space. So I had to look up that proper projection id to make sure all of the map annotations didn&apos;t appear dozens of meters away from where they should be when I went to add them to the iOS map.</p><p>After about a week of poking at this in between holiday plans and family visits, I did complete the app. It&apos;s not published on the AppStore or anything since it is really just an educational tool for me, but perhaps I will add more polish and release it some day. Check out the code and some screen grabs below, if you&apos;re interested in a little more info on some choices, features, and challenges keep scrolling past that.</p><p><a href="https://github.com/CMorooney/PSUArboretumPlantFinder?ref=calvins.pizza">Check it out on Github</a>!</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2023/12/detail-2.png" width="700" height="1518" loading="lazy" alt="Arboretum SwiftUI/TCA app" srcset="https://calvins.pizza/content/images/size/w600/2023/12/detail-2.png 600w, https://calvins.pizza/content/images/2023/12/detail-2.png 700w"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2023/12/loc_select.png" width="700" height="1518" loading="lazy" alt="Arboretum SwiftUI/TCA app" srcset="https://calvins.pizza/content/images/size/w600/2023/12/loc_select.png 600w, https://calvins.pizza/content/images/2023/12/loc_select.png 700w"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2023/12/map1-1.png" width="700" height="1518" loading="lazy" alt="Arboretum SwiftUI/TCA app" srcset="https://calvins.pizza/content/images/size/w600/2023/12/map1-1.png 600w, https://calvins.pizza/content/images/2023/12/map1-1.png 700w"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2023/12/settings_last.png" width="700" height="1518" loading="lazy" alt="Arboretum SwiftUI/TCA app" srcset="https://calvins.pizza/content/images/size/w600/2023/12/settings_last.png 600w, https://calvins.pizza/content/images/2023/12/settings_last.png 700w"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2023/12/settings_specific.png" width="700" height="1518" loading="lazy" alt="Arboretum SwiftUI/TCA app" srcset="https://calvins.pizza/content/images/size/w600/2023/12/settings_specific.png 600w, https://calvins.pizza/content/images/2023/12/settings_specific.png 700w"></div></div></div></figure><p>The app uses the latest/new SwiftUI Map to drive the main exploration view. There was one main challenge with this, however, just in that the Arboretum has a <em>lot</em> of plants on their Plant Finder map...<a href="https://github.com/CMorooney/PSUArboretumPlantFinder/issues/1?ref=calvins.pizza">my dataset is even currently missing that giant pollinator garden I mentioned earlier</a>, but still drawing all the markers on the map at once was causing some serious performance issues. You wouldn&apos;t notice it too much scrolling around the map or zooming in/out but there were two very nasty side effects. The main issue was that tapping on a map annotation seemed to be causing the map to do a redraw pass on all of its annotations before my navigation code was able to execute, causing there to be a <em>multi-second</em> delay between an annotation tap and seeing the plant detail view. The less show-stopping but equally annoying issue was that on the initial draw of all the annotations the map seemed to take a broad and then narrow phase of actually placing the annotations, causing items to be drawn in the wrong spot on app load before seemingly re-drawing and correcting itself. As a quick sanity check I reduced the amount of items being drawn from almost 3k to 10 and those bugs were gone so I knew what the culprit was for sure. I was not able to test if annotation clustering would reduce the problem since it is not yet supported on the new SwiftUI maps, but I have a suspicion it wouldn&apos;t have helped much since the underlying mapkit logic would still have to process all that data to visually cluster it.<br><br>The only way I could quickly solve this performance problem was simply to limit the user to being able to look at one area of the Arboretum at a time. The data I ripped from the web map included a <code>location</code> field for the plants that denoted (by simple string, unfortunately) where they were within the Arboretum. I added a navigation bar drop-down control so the user could select which area to view and the map would only draw the markers for that area. This change <em>significantly</em> helped those major performance issues... unfortunately some of these locations still contain a lot of data (looking at you, Children&apos;s Garden) so there is still sometimes a small but annoying nav delay for detail pages in those more dense areas but nothing close to what it was before.</p><p>Once that was all sorted I was able to try and put Realm in for the map data. I created a main AppView/Reducer to host the <a href="https://developer.apple.com/documentation/swiftui/tabview?ref=calvins.pizza">TabView</a> and read the actual data, then write it to Realm. This way the MapReducer didn&apos;t have to interact with that data layer at all, and instead subscribes to the Realm collection for the map items and just draw them, which felt a lot cleaner and makes app start up <em>super</em> snappy after the first open. I couldn&apos;t quickly find a lot of examples online for integrating Realm with the latest Composable Architecture, so I&apos;m hoping to think more on this and improve the code to be more readable and extendable over some more time....but it seems to work for okay now!</p><p>I also used Realm to store some kind of &quot;User Settings&quot; and some idea of the &quot;Last Session State&quot; so that I could allow a user to decide what portion of the Arboretum map to load on app-start, which felt like it would soften the blow of not being able to see all the data at once. The user can decide to always open the map on the last area they selected, or if they&apos;d rather, always have it open on a specific location. The latter is a little brittle since the data is all scraped and the <code>location</code> field in there are just &quot;magic strings&quot;, but I have to work with what I got. In the case of mis-aligned or missing location data the app should just fall back to using the last selected location since that is always tracked in the separate &quot;Last Session State&quot; Realm object.</p><p>And that&apos;s about it for now! I have a couple of open issues on GH as of writing this for both bugs and ways to improve the experience...hopefully I&apos;m able to do so soon!</p>]]></content:encoded></item><item><title><![CDATA[Making my first game]]></title><description><![CDATA[Making a Playdate game in a weekend for a jam!]]></description><link>https://calvins.pizza/making-my-first-game/</link><guid isPermaLink="false">66536300c644cc67bf056e03</guid><category><![CDATA[dev]]></category><category><![CDATA[games]]></category><category><![CDATA[eurorack]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Tue, 21 Nov 2023 12:05:59 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2023/11/PXL_20231113_023323783.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2023/11/PXL_20231113_023323783.jpg" alt="Making my first game"><p>I HAVE FINALLY DONE IT. So many abandoned games lay in my waste but it has always been a goal of mine to make <em>some</em> kind of video game. It&apos;s an art form I&apos;ve really come to appreciate more and more especially as I&apos;ve started and failed to complete so many over the last decade or so.</p><h2 id="background">Background</h2><hr><p>Making games is hard. A new kind of hard. Coming up with what feels like a compelling idea is a challenge in any art but making a game feels like it demands something much more -- the difficulty in hooking and maintaining player engagement sounds similar to, perhaps, writing a movie or a song but -- &#xA0;because the player is an (inter)active participant in the piece the maker is presented with a new and task of <em>creating a balanced challenge for the player</em>. The extra addition of interactivity and the expectation players have when installing any kind of video game really narrows the sweet spot of success.</p><p>Then of course there&apos;s the more obvious difficulty of just how much raw work goes into game making. Game logic must be programmed, possibly even physics simulations; art must be created -- that means the concept of characters to all the possible animations to the background to the menu screens; music must be written and recorded to fit the game; sound effects have to be carefully designed and implemented. Not only do all of these needs span across multiple (and deep) art specialties, the scale of all of it all even for a small game is overwhelmingly intimidating...and it grows <em>exponentially</em> with game complexity.</p><p>Luckily there&apos;s a lot of tools out there to help bootstrap people into game making. Fully-fledged and ubiquitous game engines like <a href="https://unity.com/?ref=calvins.pizza">Unity</a> and <a href="https://www.unrealengine.com/en-US?ref=calvins.pizza">Unreal</a> seemingly make up a large portion of indies and even some AAA games and the former even has an OpenSource alternative in the form of <a href="https://godotengine.org/?ref=calvins.pizza">Godot</a>. Engines like these at their very basic help with scene management, playing and rendering art/music, input handling, and other functionality that just about every game needs. Many (like the ones listed) go way further, adding physics simulation, lighting, pathfinding, and countless other useful tools. ALSO for the engines mentioned there are robust collections of extensions and tools other developers have made in order to improve workflow even more. That is really all to say that the complexity of making games is softened at least a little by the existence of flourishing (&amp; free) communities and tools as game making has become more accessible for folks of all skill levels.</p><p>My first game sits on the shoulders of many tools, the first being the platform itself: <a href="https://play.date/?ref=calvins.pizza">the Panic Playdate</a></p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/Playdate-photo.png" class="kg-image" alt="Making my first game" loading="lazy" width="2000" height="1530" srcset="https://calvins.pizza/content/images/size/w600/2023/11/Playdate-photo.png 600w, https://calvins.pizza/content/images/size/w1000/2023/11/Playdate-photo.png 1000w, https://calvins.pizza/content/images/size/w1600/2023/11/Playdate-photo.png 1600w, https://calvins.pizza/content/images/2023/11/Playdate-photo.png 2400w" sizes="(min-width: 720px) 720px"></figure><p>What a lovely little console. Y&apos;all know I love specialty and novel hardware and I&apos;m so glad there are designers out there still making and supporting stuff like this. The main oddities are thus: the playdate has a 1-bit (black and white only) screen with no backlight that reads closer to eink....and there&apos;s a crank. Pretty &quot;quirky&quot; or whatever! I preordered one after they were announced and waiting my long ass time to get one (the parts shortages ahhhhhhh). Since then I&apos;ve really enjoyed lurking the communities and playing as many games as I can manage -- some are truly inspiring!</p><p>The extra great thing about the playdate is that it is also a devkit. Anyone can just <a href="https://play.date/dev/?ref=calvins.pizza">download the SDK</a>, start making games, uploading them to their device, and sharing them with folks to test. It is <strong>so</strong> encouraged to make games for this console that the company who makes them created a web app for people with no programming or game dev knowledge to jump right in (called <a href="https://play.date/pulp/?ref=calvins.pizza">pulp</a>). You don&apos;t even need to have a playdate device in hand yet to give game dev a try on the platform -- the SDK comes with a simulator!</p><p>I feel that the experience developing for the playdate is not unlike the famous <a href="https://www.lexaloffle.com/pico-8.php?ref=calvins.pizza">PICO-8</a>. By imposing many limitations on the game designer and providing an easy-to-iterate experience the playdate developers are encouraged to be focused but explorative. Especially with the SDK&apos;s Lua support, trying out a quick idea just to see if it works on the console is a breeze and makes it easier and more fun to &quot;feel out&quot; what works as you discover the potential (or lack of potential) for an idea. After many failed attempts to build games in the larger engines mentioned earlier, this felt like a great place for me to be.</p><p>But I still left many unfinished playdate scribbles unfinished in my quest. I started a little pinball game, a tattooing minigame, a rhythm game, and I even tried to create an <a href="https://github.com/CMorooney/playdate_impulse?ref=calvins.pizza">impuse based physics engine</a> to use in other projects. None of them quite got finished or panned out how I liked.</p><p>Then came a nice set of coincidences. My girlfriend decided to head home to see her family one weekend and happened to tell me the moment I saw a tweet reminding me of <a href="https://itch.io/jam/playjam-4?ref=calvins.pizza">PlayJam4</a> happening over the same few days. Daylight savings time had just ended and there&apos;s a lot less daylight and warmth to go around outside so I would have plenty of time to try and <strong>complete</strong> something for this jam. The theme was announced that Friday (&quot;Your Time Is Up&quot;) and I got to scribbling.</p><h2 id="getting-started">Getting Started</h2><hr><p>All of my previous (unfinished) playdate projects had been written 100% in C for my own stubbornness and learning opportunity. I&apos;m a criminal when it comes to premature optimization and I don&apos;t get to program that low level very often so that had so far been my language of choice for playdate dev. That was going to change for this, though, as I knew I needed to be able to iterate a lot faster and not get hung up on memory issues. So, I looked around all the sample apps in the PlaydateSDK that use the Lua language and checked out existing tools that might exist for that environment.</p><p>Lucky for me, switching to Lua opened up a <em>ton</em> of libraries and examples to work from as it seems most stick to this environment for playdate dev, at least as of now. For my project I ended up using the <a href="https://github.com/NobleRobot/NobleEngine?ref=calvins.pizza">Noble Engine</a> which just made for really simple &quot;Scene&quot; and input management. It also nicely provides a <a href="https://github.com/NobleRobot/NobleEngine-ProjectTemplate?ref=calvins.pizza">template repository</a> so I just cloned that and got to it! The one other library I used was <a href="https://github.com/Whitebrim/AnimatedSprite?ref=calvins.pizza">AnimatedSprite</a> which simplifies playing sprite animations from an imagetable (a collection of images in the playdate sdk) and adds state management to sprite animations. I think NobleEngine has its own animation system that I probably should have looked into deeper but this worked out fine for me.</p><p>With the theme being declared, &quot;Your Time Is Up,&quot; the fastest idea I had on paper was only &quot;something about a grim reaper.&quot; There was a vague image in my head of a 2D platformer type game where the player would play as a grim reaper and control their scythe with 1:1 crank movement....What came would be a bit different in gameplay but the overall idea stuck.</p><h2 id="art">Art</h2><hr><p>While I had to use a lot of pre-existing assets, I did end up drawing quite a bit! Like many, I love <a href="https://www.aseprite.org/?ref=calvins.pizza">aseprite</a> so that&apos;s my pixel art editor of choice. I ended up doing the art for the main player character (a grim reaper sort) and their weapon.</p><!--kg-card-begin: html--><div style="display:flex; justify-content: center; align-items: center">
<img style="width: 42px; height: 42px;" src="blob:https://calvins.pizza/e379e13e-a5ab-4c40-8da6-1ad994f66df2" alt="Making my first game">
    <img style="width: 75px; height: 75px;" src="blob:https://calvins.pizza/6add33f9-4c0b-41de-8d49-312ecceab82e" alt="Making my first game">
</div>
<!--kg-card-end: html--><p></p><p>For other character art I would have to leverage <a href="https://opengameart.org/?ref=calvins.pizza">opengameart</a> a lot. I am not super speedy at pixel art (or any good at it in any other way) so being stubborn about painting every pixel was not going to get me across the finish line. Specifically for this game I grabbed <a href="https://opengameart.org/content/stendhal-ghost?ref=calvins.pizza">Stendhal Ghost</a> and <a href="https://opengameart.org/content/mv-platformer-male-32x64?ref=calvins.pizza">MV Platformer Male</a>.</p><p>I also did all of the environment pieces, health bars, secondary screens (game over, etc), and all the metadata art for the game (images that show up on the device for the eventual installer). Showing some examples here will also expose that the game&apos;s eventual name was <em>Scythe Shepard</em>, though that was a pretty last minute decision.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/cover-1.png" class="kg-image" alt="Making my first game" loading="lazy" width="350" height="155"></figure><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/gameplay1.png" class="kg-image" alt="Making my first game" loading="lazy" width="400" height="240"></figure><p>Lastly I did also use <a href="https://codemanu.itch.io/particle-fx-designer?ref=calvins.pizza">Pixel FX Designer</a> to create a little particle explosion sprite animation for the ghost death.</p><h2 id="gameplay">Gameplay</h2><hr><p>Initially I had imagined a single screen game with a flat floor and 3 static platforms with the idea being to survive as long as possible. There would be enemy characters appearing on the edges of the screen and following the user to attack them -- the player would have to use the crank to swing their scythe and kill an attacker. After a short time the dead attacker would turn into a ghost and start floating up towards the top of the screen. The player would need to switch to a &quot;Net&quot; weapon that behaved the same as the scythe but was used to catch ghosts and stop the ghost from leaving the top of the screen. This would give the player two game-crucial goals to balance -- don&apos;t get killed by the attackers and don&apos;t let too many ghosts get off screen. I felt this would provide enough healthy stress to the player to make it feel like a real game.</p><p>As the deadline loomed, though, I ended up changing the verticality of the idea a lot to cut down on (mostly) art work -- adding jumping animations to all the characters was a bit of a non-starter.</p><p>So, the &quot;Net&quot; weapon got scrapped, as did the 3 static platforms. Instead of the net to catch the ghosts I added some Speaker looking devices to the top of the screen and forced the ghosts to try and escape out of the middle there. Once the ghosts were close enough to their escape the user could activate the little speakers and they would kill any nearby ghosts.</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2023/11/sample.mp4" poster="https://img.spacergif.org/v1/434x276/0a/spacer.png" width="434" height="276" playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2023/11/media-thumbnail-ember630.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>This ended up being the entire gameplay loop as I was otherwise occupied with bug fixes, art, and sound; the only thing left to work out was the &quot;difficulty curve.&quot; I ended up making it so that the game was played in &quot;waves&quot; -- each wave would spawn <em>n</em> human enemies where <em>n</em> was the wave number. The number of humans spawn at once was <em>n/5</em> rounded up -- this meant that every 5 levels the game would increase the enemies spawn at <em>once</em> by one, making the player have to deal with more simultaneous threats as they progress. Simple, but effective enough in test play ... my biggest concern was players having too easy a time and having to put down the game out of boredom before it overtook them.</p><p>Speaking of play testing, this was an exciting thing to do! I wish I had more time and testers, of course, but this felt like a big moment....even if it was just my sister/BIL.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/playtesting.jpg" class="kg-image" alt="Making my first game" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/11/playtesting.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/11/playtesting.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/11/playtesting.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/11/playtesting.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><h2 id="sound">Sound</h2><hr><p>Let&apos;s get this out of the way -- I didn&apos;t have time to make music! This bums me out greatly, but I simply ran out of time and really feared making a quick loop that was just dreadful to listen to over and over. I also felt that adding music would require adding a &quot;Settings&quot; screen to allow the user to toggle the music/on and off and I didn&apos;t want to add that work either.</p><p>What I did gladly get to do is some quick sound design on the eurorack gear. Nothing very complex but here&apos;s a quick video of me trying to find the last bit of the sound that would play when a player swung the scythe and hit something (<em>note: you may need to turn your volume up a little, this might be quiet.</em>)</p><p>I really enjoyed making all the little sounds for this and next time hope to have more time to experiment and make more interesting and unique fodder -- such a unique challenge!</p><h2 id="submission-and-voting">Submission and voting</h2><hr><p>After a couple days of constant work, I turned in my game along with about 20 other folks! Some of these I was really excited to try out since some devs were posting work-in-progress stuff on twitter.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/jam_submission_page.png" class="kg-image" alt="Making my first game" loading="lazy" width="840" height="531" srcset="https://calvins.pizza/content/images/size/w600/2023/11/jam_submission_page.png 600w, https://calvins.pizza/content/images/2023/11/jam_submission_page.png 840w" sizes="(min-width: 720px) 720px"></figure><p>Now that everyone was submitted, it was time for a week-long voting phase where everyone (participators and spectators) were encouraged to try to play and rate the other games on the categories of &quot;fun,&quot; &quot;creativity,&quot; and &quot;use of console.&quot; Each game also has a comment section in the jam -- these were immediately readable while we would have to wait the full week to see any results from the ratings.</p><p>I got <em>way</em> more feedback on my game than I expected during the voting phase. I am often a little disappointed on the amount/depth of feedback I get for music so this was really fun for me. I think what helped draw in the reviews, though, were of course the contained context of the game jam, the specialty of the hardware, and the fact that games are interactive and much easier (I think) for someone to have more concrete responses to. Either way, it makes me excited to try another jam in the future! The whole community for both game dev and especially playdate dev in my experience has been so positive :]</p><p></p><p>That written feedback was so valuable to me I almost forgot about the week long numerical/categorized voting... I did end up getting 4th (out of 21) overall which ain&apos;t bad! Didn&apos;t come on top in any individual category but that doesn&apos;t surprise me or anything. Just happy I finished and people tried the game.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/Screenshot-2023-11-21-at-7.05.38-AM.png" class="kg-image" alt="Making my first game" loading="lazy" width="1220" height="344" srcset="https://calvins.pizza/content/images/size/w600/2023/11/Screenshot-2023-11-21-at-7.05.38-AM.png 600w, https://calvins.pizza/content/images/size/w1000/2023/11/Screenshot-2023-11-21-at-7.05.38-AM.png 1000w, https://calvins.pizza/content/images/2023/11/Screenshot-2023-11-21-at-7.05.38-AM.png 1220w" sizes="(min-width: 720px) 720px"></figure><p></p><p>So happy to have climbed this mountain, even if the game is pretty small. It feels real!<br></p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/11/on_hardware.jpg" class="kg-image" alt="Making my first game" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/11/on_hardware.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/11/on_hardware.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/11/on_hardware.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/11/on_hardware.jpg 2400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Building norns shield(s)]]></title><description><![CDATA[<p>I&apos;ve always admired <a href="https://monome.org/?ref=calvins.pizza">monome</a>&apos;s work but never got my hands on any of their hardware. Like a lot of folk I was mostly drawn in by their <a href="https://monome.org/docs/grid/?ref=calvins.pizza">grid</a> controller ages ago...never pulled the trigger on one of those. Got very close a few times to</p>]]></description><link>https://calvins.pizza/building-norns-shield-s/</link><guid isPermaLink="false">66536300c644cc67bf056e02</guid><category><![CDATA[projects]]></category><category><![CDATA[synth]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Wed, 06 Sep 2023 21:13:13 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2023/09/PXL_20230828_212625231.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2023/09/PXL_20230828_212625231.jpg" alt="Building norns shield(s)"><p>I&apos;ve always admired <a href="https://monome.org/?ref=calvins.pizza">monome</a>&apos;s work but never got my hands on any of their hardware. Like a lot of folk I was mostly drawn in by their <a href="https://monome.org/docs/grid/?ref=calvins.pizza">grid</a> controller ages ago...never pulled the trigger on one of those. Got very close a few times to grabbing a <a href="https://monome.org/docs/teletype/?ref=calvins.pizza">teletype</a>, and still might some day &#x2013; it would certainly make a lot of sense for me. The <a href="https://llllllll.co/?ref=calvins.pizza">lines</a> forum is a gem on its own.</p><p>What brought me first to <a href="https://monome.org/docs/norns/?ref=calvins.pizza">norns</a> though was the complete DIY spirit of the project both in hardware and software. You can buy an official machine from monome themselves (and it has many extra QOL upgrades over the raspberry-pi version I built here) but I was very interested in using this project as an excuse to try ordering PCBs from a manufacturer myself &#x2013; I&apos;ve never actually done that before!</p><p>Though no longer officially supported by monome as an open source hardware project, it was originally and the <a href="https://github.com/monome/norns-shield?ref=calvins.pizza">repo</a> is still out there. It even has a few different hardware revisions &#x2013; I chose the `210330` revision as suggested by the README and paired it with a Raspberry Pi 3B+ by the same recommendation. I should note, however, that the audio codec chip (CS4270) is marked as &quot;scheduled for obsolescence&quot; when I ordered the components from a supplier.</p><p>To my joy ordering the PCBs was actually very simple. The repo had EAGLE files and a quick web search walked me through creating the gerber files from those. Got those uploaded to some manufacturer&apos;s site, luckily they looked over it and helped correct a trivial drilling template issue, and then the boards showed up a couple weeks later!</p><!--kg-card-begin: html--><video src="https://calvins.pizza/content/media/2023/09/45379964_865571651668132_7665460577716273034_n.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="270" height="480" loop autoplay muted playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2023/09/media-thumbnail-ember276.jpg&apos;) 50% 50% / cover no-repeat; margin: 0 auto; display:block;"></video><!--kg-card-end: html--><p></p><p>I did have to order 5 PCBs minimum...gonna be giving away some norns I guess.</p><p>There was a sort of inherent trust at this point that the EAGLE files in the repo and the instructions I followed to create the drilling files were all accurate... but everything <em>looked</em> really good and clean and the right size and all that! The most reasonable way to know for sure (to me) was just to start soldering.</p><p>Though I&apos;ve done pretty tight surface mount soldering before, this felt... tinier and tighter. The biggest and most obvious worry was that 24 pin codec chip</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2023/09/PXL_20230726_183151391.jpg" class="kg-image" alt="Building norns shield(s)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/09/PXL_20230726_183151391.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/09/PXL_20230726_183151391.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/09/PXL_20230726_183151391.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/09/PXL_20230726_183151391.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>that&apos;s my pinky finger</figcaption></figure><p>And for the sake of honesty I did burn through one of these codec chips and had to order another...I also then waited for smaller solder tips and thinner solder to arrive which would prove very helpful &#x2013; I did not burn another chip!</p><!--kg-card-begin: html--><video src="https://calvins.pizza/content/media/2023/09/PXL_20230803_172942881.mp4" poster="https://img.spacergif.org/v1/1080x1920/0a/spacer.png" width="270" height="480" loop autoplay muted playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2023/09/media-thumbnail-ember322.jpg&apos;) 50% 50% / cover no-repeat; margin: 0 auto; display: block"></video><!--kg-card-end: html--><p>Finally got it. The other nice thing about having the EAGLE files for the boards was that it was very easy for me to see where the pins were connected and test to make sure everything was solid and nothing was shorted. There are a lot of snake bites on the board for that already but it was nice to just use the board file to be sure.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2023/09/PXL_20230818_201511014.jpg" class="kg-image" alt="Building norns shield(s)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/09/PXL_20230818_201511014.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/09/PXL_20230818_201511014.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/09/PXL_20230818_201511014.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/09/PXL_20230818_201511014.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>first try!</figcaption></figure><p>The rest of the work was pretty boring surface mount stuff, one particularly annoying clock...a lot of the tightness of the layout was relieved by the smaller tips &amp; solder I ended up buying.</p><p>Even testing as I went I did have a few panic moments, though &#x2013; the first norns I put together didn&apos;t seem to boot. I followed the <a href="https://monome.org/docs/norns/help/?ref=calvins.pizza">troubleshooting</a> section of the monome site and was able to deduce that the machine <em>was</em> booting, I just wasn&apos;t seeing anything on the display. A quick re-flow of the screen component and I was up and running!</p><p>The second I built didn&apos;t boot at all at first, which was certainly concerning. I did the typical thing &#x2013; took a long break, came back, and very closely looked at every joint and re-flowed any suspicious ones. It booted! But it displayed an error message about the audio server (jack) not being able to start. Assuming this would be an issue with the codec chip, I went back to testing those pins again. Turns out the reflow that fixed the boot also bridged a subsequent connected pad to a (very) nearby ground snakebite. Sucked that up, <em>carefully</em> reapplied solder, retested, and we were good to go.</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/09/PXL_20230828_212625231-1.jpg" class="kg-image" alt="Building norns shield(s)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/09/PXL_20230828_212625231-1.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/09/PXL_20230828_212625231-1.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/09/PXL_20230828_212625231-1.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/09/PXL_20230828_212625231-1.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>I whipped another up right after the first one worked because I was going on a little music-writing trip with a friend who&apos;s birthday was also coming up and felt he might appreciate some of the odd norns scripts/apps out there.</p><p>The case is 3D printed, maybe someday I&apos;ll make something nicer for an enclosure. To be honest, I&apos;d like to get to writing apps for it first but even now my eyes are on other music-related projects so I&apos;ll have to come back to the norns to dig deeper.</p><p>Until then I&apos;m really excited to check out the existing community scripts and I&apos;m happy to have unlocked &quot;using a PCB manufacturer.&quot;</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/09/PXL_20230906_194240072.jpg" class="kg-image" alt="Building norns shield(s)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2023/09/PXL_20230906_194240072.jpg 600w, https://calvins.pizza/content/images/size/w1000/2023/09/PXL_20230906_194240072.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2023/09/PXL_20230906_194240072.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2023/09/PXL_20230906_194240072.jpg 2400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA["GoodReads for Games" with Obsidan.md]]></title><description><![CDATA[use Obsidian to manage your game backlog and notes with these 2 plugins!]]></description><link>https://calvins.pizza/goodreads-for-games-with-obsidan-md/</link><guid isPermaLink="false">66536300c644cc67bf056e01</guid><category><![CDATA[dev]]></category><category><![CDATA[games]]></category><dc:creator><![CDATA[Calvin Morooney]]></dc:creator><pubDate>Thu, 11 May 2023 23:40:32 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2023/05/Screenshot-2023-05-11-at-6.23.25-PM.png" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2023/05/Screenshot-2023-05-11-at-6.23.25-PM.png" alt="&quot;GoodReads for Games&quot; with Obsidan.md"><p>I love <a href="https://obsidian.md/?ref=calvins.pizza">Obsidian</a>. I use it to keep longer term reference notes for work and for personal projects. I&apos;m hardly a power user though, some people go pretty heavy, its a very powerful tool with a dense community plugin repository.<br><br>Elsewhere I also have been constantly frustrated that there isn&apos;t a simple video game backlog management website/app/service. Something close to <a href="https://www.goodreads.com/?ref=calvins.pizza">goodreads</a> in simplicity of managing your &quot;shelves&quot; of books.</p><p>Then - poof - I came across several Obsidian tutorials (<a href="https://www.youtube.com/watch?v=7PFFJlyiv28&amp;t=19s&amp;pp=ygUSb2JzaWRpYW4gZ29vZHJlYWRz&amp;ref=calvins.pizza">like this one</a>) where folks were using the community plugins <a href="https://obsidian.md/plugins?id=dataview&amp;ref=calvins.pizza">dataview</a> and <a href="https://obsidian.md/plugins?id=obsidian-book-search-plugin&amp;ref=calvins.pizza">book search</a> to create and manage their own book backlog &amp; reviews. This was perfect: I didn&apos;t need or want the social features of goodreads, just the ability to list and organize some metadata around games with some degree of flexibility. Obsidian was again the answer.</p><p>There was no <code>game search</code> plugin to match <code>book search</code>, but luck would grace me again as not only is <code>book search</code> <a href="https://github.com/anpigon/obsidian-book-search-plugin?ref=calvins.pizza">open source</a> but the code is also very clean! So I quickly forked it annndddd....</p><p><a href="https://obsidian.md/plugins?id=game-search&amp;ref=calvins.pizza">here&apos;s the link for the game search Obsidian plugin</a></p><p><a href="https://github.com/CMorooney/obsidian-game-search-plugin?ref=calvins.pizza">and here is the Github</a></p><h2 id="installation-configuration">Installation &amp; Configuration</h2><p><code>game search</code> can be installed from within Obsidian community plugins and must be provided at least a <code>RAWG Api Key</code> in the plugin settings. You can request an API key from RAWG <a href="https://rawg.io/apidocs?ref=calvins.pizza">here</a>. If other API providers are desired feel free to open a github issue!</p><p>I do recommend also changing the settings to use a new folder for your new game files so they don&apos;t crowd your vault. It&apos;s also recommended to provide a <a href="https://help.obsidian.md/Plugins/Templates?ref=calvins.pizza">template file</a> in the settings to insert <a href="https://help.obsidian.md/Editing+and+formatting/Metadata?ref=calvins.pizza">yaml metadata</a> to your game notes so that you can query them with <code>dataview</code>. The available properties returned from the RAWG Api and an example template file are in the <a href="https://github.com/CMorooney/obsidian-game-search-plugin/blob/master/README.md?ref=calvins.pizza">README of the repo</a>.</p><p>The plugin adds a command to the palette, &quot;add new game note.&quot; This brings up a text search which, when executed, will result in a list of suggestions of games accompanied by their release year to help distinguish any similar titles. Selecting one of those creates a new note for that game in your vault!</p><p>I keep it pretty simple &#x2013; here&apos;s what my &quot;game shelf&quot; looks like (<code>dataview</code> code example below):</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2023/05/Screenshot-2023-05-11-at-6.40.28-PM.png" class="kg-image" alt="&quot;GoodReads for Games&quot; with Obsidan.md" loading="lazy" width="803" height="1318" srcset="https://calvins.pizza/content/images/size/w600/2023/05/Screenshot-2023-05-11-at-6.40.28-PM.png 600w, https://calvins.pizza/content/images/2023/05/Screenshot-2023-05-11-at-6.40.28-PM.png 803w" sizes="(min-width: 720px) 720px"></figure><p>the data view for &quot;Playing&quot; section, for example:</p><!--kg-card-begin: html-->```dataview

Table (&quot;![|350](&quot; + background_image + &quot;)&quot;) as Image, genres

From &quot;games&quot;

Where contains(status, &quot;playing&quot;)
```<!--kg-card-end: html--><p></p><p>That&apos;s that! I got what I wanted &#x2013; a very simple (and local!) way to manage my own little game backlog, notes, and reviews. With what comes back from the RAWG Api and the power of <code>dataview</code> I expect you might be able to push it a bit further if you&apos;d like. If there&apos;s anything missing (or broken!) feel free to open a Github issue :]</p>]]></content:encoded></item><item><title><![CDATA[Building the Mainbow (v2)]]></title><description><![CDATA[building video synth modules!]]></description><link>https://calvins.pizza/building-the-mainbow-v2/</link><guid isPermaLink="false">66536300c644cc67bf056e00</guid><category><![CDATA[eurorack]]></category><category><![CDATA[projects]]></category><category><![CDATA[video]]></category><dc:creator><![CDATA[Calvin]]></dc:creator><pubDate>Wed, 14 Dec 2022 16:24:23 GMT</pubDate><media:content url="https://calvins.pizza/content/images/2022/12/PXL_20221109_034129987-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://calvins.pizza/content/images/2022/12/PXL_20221109_034129987-1.jpg" alt="Building the Mainbow (v2)"><p>Because I am restless I have begun to expand my eurorack format gear into the wild, expensive, and rare world of ~Video Synthesis~<br></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://media.tenor.com/SU3d8GibT6YAAAAC/rip-lzx.gif" class="kg-image" alt="Building the Mainbow (v2)" loading="lazy" width="498" height="280"><figcaption>(this is not from my gear)</figcaption></figure><p>While I have been slowly gathering some <a href="https://lzxindustries.net/?ref=calvins.pizza">LZX</a> modules after their <a href="https://community.lzxindustries.net/t/lzx-gen3-primer-faq-the-future-with-chromagnon-lzx-modular/3688?ref=calvins.pizza">GEN3 modules</a> started rolling out, I&apos;ve also been hanging out* on the LZX discord which has been helping me find other video synth makers. It&apos;s seemingly a much more DIY community than your typical eurorack group (which is saying something) so finding all these individual bespoke creators not only fun, but crucial.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text">* seriously how do people keep up with Discord servers as social media? Can we please go back to forums I can&apos;t keep up with y&apos;all</div></div><p>The first non-LZX, non-prebuilt video gear I picked up was the <a href="https://www.etsy.com/listing/1005042852/mainbow-analog-video-synth-eurorack?show_sold_out_detail=1&amp;ref=nla_listing_details">Mainbow from Chroma Cauldron</a>. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2022/12/il_794xN.4296405114_1gj0.webp" class="kg-image" alt="Building the Mainbow (v2)" loading="lazy" width="794" height="393" srcset="https://calvins.pizza/content/images/size/w600/2022/12/il_794xN.4296405114_1gj0.webp 600w, https://calvins.pizza/content/images/2022/12/il_794xN.4296405114_1gj0.webp 794w" sizes="(min-width: 720px) 720px"><figcaption>this is chroma cauldron&apos;s product image</figcaption></figure><p>Aside from the attractive price for the features, I just wanted to do something more DIY and this machine included some cool features I wanted like external video input/processing and a basic audio analyzer to incorporate some more reactive elements from my audio tools.</p><p>One of the best parts &#x2013; I must say &#x2013; was the packaging of the kit itself. The PCB and the faceplate were wrapped and protected while ever other part was stapled to an enlarged BOM where it was marked what the part was and how many you should have. It basically took out the first 45 minutes or so of organizing and preparing that usually comes with pulling out a kit. </p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221105_144831010.jpg" width="2000" height="2656" loading="lazy" alt="Building the Mainbow (v2)" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221105_144831010.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221105_144831010.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221105_144831010.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221105_144831010.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221105_145159209-1.jpg" width="2000" height="1506" loading="lazy" alt="Building the Mainbow (v2)" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221105_145159209-1.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221105_145159209-1.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221105_145159209-1.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221105_145159209-1.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221105_145208915-1.jpg" width="2000" height="1506" loading="lazy" alt="Building the Mainbow (v2)" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221105_145208915-1.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221105_145208915-1.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221105_145208915-1.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221105_145208915-1.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><p>There was even an error in one of the resistor values on the silkscreen of the PCB so that single resister came pre-soldered to avoid any confusion with having to put a &apos;wrong&apos; resistor in yourself according to the labeling. Top notch thoughtfulness.<br></p><p>Then of course the PCB layout itself was really well designed. All the resistors are in a neat row &amp; everything was clearly marked &#x2013; I had no issues whatsoever putting this together it almost felt too easy.</p><figure class="kg-card kg-gallery-card kg-width-wide"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221107_211424298.jpg" width="2000" height="2656" loading="lazy" alt="Building the Mainbow (v2)" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221107_211424298.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221107_211424298.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221107_211424298.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221107_211424298.jpg 2400w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221108_102628831.jpg" width="2000" height="2656" loading="lazy" alt="Building the Mainbow (v2)" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221108_102628831.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221108_102628831.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221108_102628831.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221108_102628831.jpg 2400w" sizes="(min-width: 720px) 720px"></div></div></div></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221109_034129987.jpg" class="kg-image" alt="Building the Mainbow (v2)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221109_034129987.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221109_034129987.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221109_034129987.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221109_034129987.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>!!</figcaption></figure><p>and so it came to plugging in and testing (without external input).</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2022/12/PXL_20221109_235048539.LS.mp4" poster="https://img.spacergif.org/v1/768x1024/0a/spacer.png" width="768" height="1024" loop autoplay muted playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2022/12/media-thumbnail-ember435.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container kg-video-hide"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>and then with external video! Here I plugged the output of a VCR playing an X-Files episode in and made it all liquid</p><figure class="kg-card kg-video-card"><div class="kg-video-container"><video src="https://calvins.pizza/content/media/2022/12/PXL_20221120_224522157.mp4" poster="https://img.spacergif.org/v1/1920x1080/0a/spacer.png" width="1920" height="1080" loop autoplay muted playsinline preload="metadata" style="background: transparent url(&apos;https://calvins.pizza/content/images/2022/12/media-thumbnail-ember491.jpg&apos;) 50% 50% / cover no-repeat;"></video><div class="kg-video-overlay"><button class="kg-video-large-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button></div><div class="kg-video-player-container kg-video-hide"><div class="kg-video-player"><button class="kg-video-play-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M23.14 10.608 2.253.164A1.559 1.559 0 0 0 0 1.557v20.887a1.558 1.558 0 0 0 2.253 1.392L23.14 13.393a1.557 1.557 0 0 0 0-2.785Z"/></svg></button><button class="kg-video-pause-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><rect x="3" y="1" width="7" height="22" rx="1.5" ry="1.5"/><rect x="14" y="1" width="7" height="22" rx="1.5" ry="1.5"/></svg></button><span class="kg-video-current-time">0:00</span><div class="kg-video-time">/<span class="kg-video-duration"></span></div><input type="range" class="kg-video-seek-slider" max="100" value="0"><button class="kg-video-playback-rate">1&#xD7;</button><button class="kg-video-unmute-icon"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M15.189 2.021a9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h1.794a.249.249 0 0 1 .221.133 9.73 9.73 0 0 0 7.924 4.85h.06a1 1 0 0 0 1-1V3.02a1 1 0 0 0-1.06-.998Z"/></svg></button><button class="kg-video-mute-icon kg-video-hide"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"><path d="M16.177 4.3a.248.248 0 0 0 .073-.176v-1.1a1 1 0 0 0-1.061-1 9.728 9.728 0 0 0-7.924 4.85.249.249 0 0 1-.221.133H5.25a3 3 0 0 0-3 3v2a3 3 0 0 0 3 3h.114a.251.251 0 0 0 .177-.073ZM23.707 1.706A1 1 0 0 0 22.293.292l-22 22a1 1 0 0 0 0 1.414l.009.009a1 1 0 0 0 1.405-.009l6.63-6.631A.251.251 0 0 1 8.515 17a.245.245 0 0 1 .177.075 10.081 10.081 0 0 0 6.5 2.92 1 1 0 0 0 1.061-1V9.266a.247.247 0 0 1 .073-.176Z"/></svg></button><input type="range" class="kg-video-volume-slider" max="100" value="100"></div></div></div></figure><p>So much fun! Now I just need to add more power and space to the existing LZX rack...</p><figure class="kg-card kg-image-card"><img src="https://calvins.pizza/content/images/2022/12/PXL_20221214_162105957.jpg" class="kg-image" alt="Building the Mainbow (v2)" loading="lazy" width="2000" height="2656" srcset="https://calvins.pizza/content/images/size/w600/2022/12/PXL_20221214_162105957.jpg 600w, https://calvins.pizza/content/images/size/w1000/2022/12/PXL_20221214_162105957.jpg 1000w, https://calvins.pizza/content/images/size/w1600/2022/12/PXL_20221214_162105957.jpg 1600w, https://calvins.pizza/content/images/size/w2400/2022/12/PXL_20221214_162105957.jpg 2400w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item></channel></rss>