<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>My Blog</title>
    <link>https://hgs3.me/</link>
    
        <entry>
            <title>Semy: The Semantic Version Parser for C11</title>
            <link>https://hgs3.me//journal/semy-the-semantic-version-parser-for-c11</link>
            <updated>Wed, 04 Feb 2026 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Semy (rhymes with <em>Remy</em>) is a Semantic Version 2.0.0 (SemVer) parser and processor.
It is both a C library and a command-line interface.</p>
<p>You can use Semy to validate semantic versions, extract version identifiers, check if two versions are equal, and check if a version is newer or older than another.</p>
<h2 id="why?">Why?<a href="#why?">#</a></h2>
<p>I wrote Semy because I have multiple projects that require a semantic version parser.
Semy was purpose built for those needs.</p>
<h2 id="technical-tidbits">Technical Tidbits<a href="#technical-tidbits">#</a></h2>
<p>I developed Semy as a single header/source implementation so it’s easily vendored into my own (and your own) projects.
It also includes CMake and Autotools build scripts for traditional compilation and installation.</p>
<p>According to the SemVer specification, there is no length limit on the number of pre-release and build identifiers a semantic version can have.
I wrote Semy without dynamic memory allocation, so the implementation <em>does</em> assume a maximum size, however, that limit will <em>never</em> be realistically hit in practice.</p>
<p>Semy is extensively tested:</p>
<ul>
<li>Unit tests with 100% code coverage</li>
<li>Fuzz tests (libFuzzer and AFL++)</li>
<li>Code sanitizers (UBSAN, ASAN, and MSAN)</li>
<li>Extensive run-time checks</li>
</ul>
<p>The SemVer specification is published at <a href="https://semver.org/">https://semver.org/</a>.</p>
<h2 id="the-initial-release">The Initial Release<a href="#the-initial-release">#</a></h2>
<p>I released Semy at version 0.9.0 because it’s well tested and “stable,” but I’d like its API to bake in the wild before I commit (pun intended) to a 1.0.0 release.</p>
<p>Semy is available under the MIT License.
Its code is published at <a href="https://github.com/hgs3/semy">https://github.com/hgs3/semy</a>.</p>]]></content>
        </entry>
    
        <entry>
            <title>The Dark Side of ‘Preparation Meets Opportunity’</title>
            <link>https://hgs3.me//journal/the-dark-side-of-preparation-meets-opportunity</link>
            <updated>Fri, 30 Jan 2026 00:00:00 </updated>
            <content type="html"><![CDATA[<p>The adage “Luck is what happens when preparation meets opportunity” is everywhere.
I’ve seen it on classroom posters, heard it in corporate workshops, and read it in many self-help books. 
This phrase has bothered me for years.
It’s one of those “truthy” statements that feels profound until you pull at the threads.</p>
<p>The quote is widely attributed to the Roman Stoic philosopher Seneca.
Well, sorry Mr. Seneca, but I’m going to disagree.</p>
<h2 id="it-assumes-preparation-is-a-prerequisite">It Assumes Preparation is a Prerequisite<a href="#it-assumes-preparation-is-a-prerequisite">#</a></h2>
<p>Not all luck requires preparation.
A baby born into a billionaire family didn’t do “pre-birth preparatory work” to secure their inheritance.
If you find a $100 bill on the sidewalk during your routine walk to the grocer, your “readiness” didn’t put it there.</p>
<p>The quote implies that luck is earned, but it’s often unearned, unasked for, and unexpected.</p>
<h2 id="it-ignores-bad-luck">It Ignores Bad Luck<a href="#it-ignores-bad-luck">#</a></h2>
<p>The adage implicitly assumes luck is a positive force, but in reality it’s a spectrum. </p>
<p>A cancer diagnosis, a house destroyed by a tornado, or a freak accident aren’t the result of “bad preparation.” 
They are instances of randomness.
You can be the most prepared person in the world and still be sidelined by a black swan event.
To use Seneca’s logic, we would have to imply that victims of misfortune simply weren’t “ready” for a better outcome.</p>
<h2 id="it-glosses-over-systemic-inequality">It Glosses Over Systemic Inequality<a href="#it-glosses-over-systemic-inequality">#</a></h2>
<p>There is a hidden assumption that everyone is eventually presented with a “big break.”
Unfortunately, opportunity is not distributed equally.
While technically anyone born in the U.S. could become President, the statistical reality is tied heavily to one’s starting point.</p>
<h2 id="the-math-of-failure">The Math of Failure<a href="#the-math-of-failure">#</a></h2>
<p>If success were truly a matter of “preparation meeting opportunity,” we would see a much higher correlation between hard work and success.
Instead, the data tells a story of attrition.</p>
<h3 id="business-failure">Business Failure<a href="#business-failure">#</a></h3>
<p>According to the U.S. Bureau of Labor Statistics, roughly 20% of businesses fail in their first year, and a staggering 65% are gone by year ten.
Are we to believe that 65% of people who put their life savings and years of effort into a business simply “weren’t prepared”? </p>
<p>Or is it more likely they were met with a “bad luck” event they couldn’t control.
When we use Seneca’s logic, we are forced to tell these millions of people that their failure was a personal lack of readiness, rather than the statistical reality of a volatile market.</p>
<h3 id="creative-failure">Creative Failure<a href="#creative-failure">#</a></h3>
<p>We call creative industries ‘hit-driven’ for a reason.
‘Hits’ are the intersection of talent and timing, and timing is just another word for luck.</p>
<ul>
<li><strong>Art:</strong> 75% of independent visual artists make <strong>less than $10,000 a year</strong>. <sup><a href="https://news.artnet.com/market/artists-make-less-10k-year-1162295">[1]</a></sup></li>
<li><strong>Music:</strong> Only <strong>0.4%</strong> of artists earn a living wage from streaming royalties. <sup><a href="https://musictech.com/news/industry/uk-govt-study-reveals-0-4-per-cent-of-artists-make-a-living-from-streaming-revenue/">[2]</a></sup></li>
<li><strong>Games:</strong> Over 50% of indie games released on Steam earned less than $1,000 in total lifetime revenue. The top <strong>0.5%</strong> account for <strong>80% of all revenue</strong>! <sup><a href="https://wnhub.io/news/stores-and-publishing/item-42136">[3]</a></sup></li>
</ul>
<p>To suggest these passionate people “weren’t prepared” is an insult to their craft.</p>
<h2 id="the-real-definition-of-luck">The Real Definition of Luck<a href="#the-real-definition-of-luck">#</a></h2>
<p>Luck is <strong>randomness that affects you.</strong>
It is a <em>neutral</em> force.
It can be a tailwind or a headwind.</p>
<h2 id="why-does-the-quote-persist?">Why Does The Quote Persist?<a href="#why-does-the-quote-persist?">#</a></h2>
<p>If the logic of the adage is so flawed, why do we keep repeating it?
I think the answer is simple: it gives us the <strong>illusion of agency.</strong>
We want to believe we are the pilots of our lives.
It’s comforting to think that if we work <em>hard enough</em> and stay <em>ready</em> we can manifest success.
It turns a chaotic, unfair world into a meritocracy.</p>
<h2 id="why-this-matters">Why This Matters<a href="#why-this-matters">#</a></h2>
<p>I felt compelled to write this because, while the quote is intended to be inspirational, it has a dark side: <strong>it shifts blame.</strong></p>
<p>When we define luck as “preparation meeting opportunity,” the inverse becomes a weapon.
It becomes a silencer for those raising their hands about systemic barriers.
It creates guilt and shame in the minds of founders and creatives, like a form of gaslighting.
It tells us to look at the successful and say they <em>deserved</em> it, and look at the struggling and say they <em>missed</em> it.</p>
<h2 id="preparation-is-still-necessary-(but-not-a-guarantee)">Preparation is Still Necessary (But Not a Guarantee)<a href="#preparation-is-still-necessary-(but-not-a-guarantee)">#</a></h2>
<p>Despite my misgivings, this is not a call to nihilism.
Success is like a lottery: years of preparatory work are the price of the ticket.
If you don’t prepare, you aren’t even in the drawing.</p>
<p>You should absolutely hone your craft and work your hardest, not because it guarantees a win, but because it’s the only way to be eligible if lightning strikes.
But we need to stop lying to the people standing in line, telling them that the harder they grip their ticket, the more likely the universe is to pick their number.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>Seneca’s intent was to encourage perseverance.
Unfortunately, his adage has morphed into a tool for survivor bias and contributes to the just-world fallacy. <sup><a href="https://en.wikipedia.org/wiki/Just-world_fallacy">[4]</a></sup></p>
<p>For many, “opportunity” is actually a safety net provided by a wealthy family or benefactor, allowing for years of “preparation” that others cannot afford.
For others, luck is lightning in a bottle, and it is doubtful that even the “survivors” could repeat their success if they had to restart from zero.</p>
<p>It is far more honest and empathetic to acknowledge luck for what it is: a random force of nature.
We can control our effort, but we can’t control the wind.</p>]]></content>
        </entry>
    
        <entry>
            <title>Digital Graphics: My Five-Month Progression</title>
            <link>https://hgs3.me//journal/digital-graphics-my-five-month-progression</link>
            <updated>Mon, 29 Dec 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>I’m no stranger to digital media, but I’m far from an expert.
I’d never taken a formal course in the subject until this past semester</p>
<p>I enrolled in an introductory Photoshop and Illustrator course at my local university.
It’s been <em>at least</em> a decade since I used them (I prefer the free alternatives, i.e. Inkscape, Krita).</p>
<p>Photoshop was about as good (and buggy) as I remember it, but now with AI tools.
Illustrator I’d barely used in the past, but it functioned similarly enough to Inkscape so I picked it up quickly.</p>
<h2 id="alien-lo-fi-animation">Alien Lo-fi Animation<a href="#alien-lo-fi-animation">#</a></h2>
<p>The most interesting assignment in the course was the final assignment: to make a lo-fi animation.</p>
<p>I’m no expert in animation.
Most of the animations I’ve produced were for simple video games I programmed as a teenager and those on the landing page of Railgun Labs, but that’s precisely what made the assignment so much fun!</p>
<p>The animation I created is a looping lo-fi animation of an alien in their spaceship passing by our solar system.</p>
<iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" frameborder="0" height="315" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/ggqcc6qe0Vc?si=3mSXAm1WMhc-Xy1j" title="YouTube video player" width="560"></iframe>
<p>It’s not perfect by any means (there’s lots of visual artifacts), but it’s something I’m proud of.
I missed one class day due to being out sick, but if that hadn’t happened, I’m sure I could have taken it to the next level.</p>
<p>I drew the entire animation by hand with a Wacom drawing tablet.
I’d never used a drawing tablet prior to the course.
For the most part, it was like drawing with pencil and paper except more forgiving as I could <em>easily</em> undo my mistakes.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>I don’t have the opportunity to make many animations, so I very much enjoyed the final assignment.
And, based on the experience, I think I will invest in my own drawing tablet.</p>]]></content>
        </entry>
    
        <entry>
            <title>Root Beer Review: Cicero Salted Caramel Root Beer</title>
            <link>https://hgs3.me//journal/root-beer-review-cicero-salted-caramel-root-beer</link>
            <updated>Mon, 24 Nov 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Cicero Salted Caramel Root Beer is my <em>favorite</em> caramel root beer.</p>
<p>When I first heard there was such a thing as “caramel root beer” I was immediately apprehensive.
I like caramel, and I like root beer, but there’s no way those flavors mix... or so I thought.
When I finally tried one, I found myself enjoying it!
There are several caramel root beers out there, but in this post I wanted to highlight my favorite which is Cicero’s.</p>
<p>The problem with many caramel root beers is the flavor ratio is asymmetric — either too much caramel or too much root beer.
Cicero, however, strikes the perfect balance, I’d say about 50/50 even.
You can <em>easily</em> distinguish the caramel and root beer flavors when you drink it.</p>
<p>The soda has a mild bite and decent froth when poured.
The root beer flavor, even on its own, is very solid with vanilla and mild spiciness.
The caramel is great too with a touch of saltiness further elevating it.
There’s a great amount of carbonation; you can feel it bubbling on your tongue.</p>
<p>The color is a perfect caramel-to-dark amber hue, similar to a traditional root beer but with more of a golden, caramel-toned glow.
The smell of the beverage <em>is</em> strongly dominated by the caramel, but that’s not a bad thing.
And although the root beer-to-caramel flavoring is balanced when drinking, the aftertaste <em>does</em> lean caramel.
My final verdict is if you like caramel and Root Beer, then I’d strongly recommend it.</p>
<p>Rating: <strong>A Tier</strong></p>]]></content>
        </entry>
    
        <entry>
            <title>Black Thunder Chocolate Bar Copycat Recipe</title>
            <link>https://hgs3.me//journal/black-thunder-chocolate-bar-copycat-recipe</link>
            <updated>Sat, 23 Aug 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Black Thunder is a chocolate bar made and sold in Japan by the Yuraku Confectionery Company.
While I don’t live in Japan, I stumbled upon them at a local Asian grocery store and bought a pack on a whim.</p>
<p>Little did I know what I got myself into.
These bars are incredibly addictive.
You can’t eat just one.</p>
<figure>
<img alt="Black Thunder" height="198" loading="lazy" src="/assets/black-thunder.png" width="447"/>
<figcaption>Black Thunder chocolate bars.</figcaption>
</figure>
<p>My copycat recipe attempts to reproduce the bars using only five ingredients found at your local grocery store.
And they can be prepared in less than 10 minutes!</p>
<p>The general idea behind my recipe is to create a melted chocolate-peanut butter mixture, then add graham crackers and Rice Krispies for crunch.</p>
<p>I recommend melting the chocolate on its own, without adding butter, cream, or condensed milk.
I’ve observed that those extra ingredients introduce moisture, which can soften the Rice Krispies and graham crackers, taking away their satisfying crunch.</p>
<p>While I like to melt the chocolate in a wok, you can also use a double boiler or even the microwave if you prefer.</p>
<h2 id="ingredients">Ingredients<a href="#ingredients">#</a></h2>
<ul>
<li>2 cups semi-sweet chocolate chips</li>
<li>1 tablespoon creamy peanut butter</li>
<li>1 teaspoon brown sugar (light or dark, depending on your tastes)</li>
<li>1 cup Rice Krispies</li>
<li>1 cup Chocolate Teddy Grahams <sup>[1]</sup></li>
</ul>
<p><sup>[1]</sup> If you cannot find Chocolate Teddy Grahams you can use chopped-up Honey Maid Chocolate Graham Crackers as a substitute.</p>
<h2 id="steps">Steps<a href="#steps">#</a></h2>
<ol>
<li>Melt <strong>2 cups semi-sweet chocolate chips</strong> over low heat in a non-stick pan or wok until smooth. Constantly stir the chocolate so it doesn’t burn.</li>
<li>Add <strong>1 tablespoon creamy peanut butter</strong> and <strong>1 teaspoon brown sugar</strong> to the melted chocolate and mix together until blended.</li>
<li>Remove the mixture from the heat and add <strong>1 cup Rice Krispies</strong> and <strong>1 cup Chocolate Teddy Grahams</strong>. Stir until these dry ingredients are coated by the chocolate mixture.</li>
<li>Transfer to an 8x8 baking dish lined with parchment paper and store in the fridge until solid (2 to 3 hours).</li>
<li>Remove the solid chocolate mixture from the fridge, cut into candy bars, and store in an airtight container in a cool, dark place.</li>
</ol>]]></content>
        </entry>
    
        <entry>
            <title>Unmasking the ECS Design Pattern: A Re-invention of Existing Concepts?</title>
            <link>https://hgs3.me//journal/unmasking-the-ecs-design-pattern</link>
            <updated>Sun, 20 Jul 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>The <strong>Entity Component System</strong> (ECS) design pattern is popular with game developers.
It’s celebrated as a modern data-oriented paradigm, standing in stark contrast to traditional Object-Oriented Programming (OOP).
But what if ECS isn’t an entirely novel invention?
What if it’s actually a clever re-packaging of long-standing programming concepts, driven by the unique needs of game development?</p>
<h2 id="the-ecs-design-pattern">The ECS Design Pattern<a href="#the-ecs-design-pattern">#</a></h2>
<p>Let’s begin with a quick refresher on what ECS is, conceptually:</p>
<dl>
<dt>Entity</dt>
<dd>It represents a “thing” in a game (e.g. a player, a tree, a bullet). Think of it as an empty container.</dd>
<dt>Component</dt>
<dd>This is pure data. It describes a specific attribute of an entity (e.g. <code>Position{ x, y, z }</code> or <code>Health{ value }</code>). An entity gains capabilities by having components attached to it.</dd>
<dt>System</dt>
<dd>This is pure logic. It processes entities with a specific set of components and performs operations on that component data. For example, a “movement system” might process all entities that have both a <code>Position</code> and a <code>Velocity</code> component.</dd>
</dl>
<h2 id="design-patterns-as-missing-language-features">Design Patterns as Missing Language Features<a href="#design-patterns-as-missing-language-features">#</a></h2>
<p>A <a href="https://en.wikipedia.org/wiki/Software_design_pattern">design pattern</a> is a general, reusable solution to a common problem that occurs within a given context in software design.
There have been many books published about design patterns, one of the most famous being the “Gang of Four” book.</p>
<p>One of the criticisms of design patterns is that many of them appear to be workarounds for missing language features.
Peter Norvig demonstrated that 16 of the 23 classic design patterns in the “Gang of Four” book are either simplified or eliminated by more powerful language constructs.
This is further reinforced by various academic papers like <em>"On the Interaction of Object‑Oriented Design Patterns and Programming Languages"</em> by Gerald Baumgartner, Konstantin Läufer, and Vincent F. Russo.</p>
<p>This makes me wonder: What underlying language features is the ECS design pattern effectively a workaround or implementation of?</p>
<h3 id="mixins">Mixins<a href="#mixins">#</a></h3>
<p><a href="https://en.wikipedia.org/wiki/Mixin">Mixins</a> are an object-oriented concept that allows a programmer to inject some code into a class.
Instead of reusing code through inheritance, you “mix in” the code into the class instead.</p>
<p>Mixins were introduced by the <em>Flavors</em> programming language, an early object-oriented extension to Lisp.
Its creator, Howard Cannon, was inspired by a local Ice Cream Parlor shop which offered basic flavors of ice cream (vanilla, chocolate, etc.) and blended them into a combination of extra items (nuts, chocolate chips, fudge, etc.).
These extra items were called “mix-ins".</p>
<p>Bringing this back to ECS: The <strong>Entity</strong> is the ice cream and the <strong>Component</strong> is the “mix-in".
The idea is you take your ice cream (the entity) and mix-in the nuts and chocolate chips (the components).
More technically, you take a <code>Player</code> entity and mix-in a <code>Position</code> and <code>Health</code> components.</p>
<h3 id="reflection">Reflection<a href="#reflection">#</a></h3>
<p><a href="https://en.wikipedia.org/wiki/Reflective_programming">Reflection</a> is the ability for a programming language to examine and modify its own structure and behavior at runtime.
In object-oriented programming languages, reflection might allow the inspection and modification of classes, interfaces, fields, and methods.</p>
<p>In languages with mixins, reflection could allow the addition or removal of mixins from objects at runtime.
Reflection could also be used to check which mixins an object has before passing them off to a function that operates on them.</p>
<h2 id="connecting-the-features">Connecting the Features<a href="#connecting-the-features">#</a></h2>
<p>Suppose we have a multi-paradigm programming language that has objects, free functions, and supports both mixins and reflection.
In such a hypothetical language, we could reproduce the ECS pattern using native features:</p>
<dl>
<dt>Entity</dt>
<dd>This is an “empty” object (e.g. a <code>Player</code> object).</dd>
<dt>Component</dt>
<dd>This is an object with state (your “mix-ins,” like a <code>Position</code> or <code>Health</code> object).</dd>
<dt>System</dt>
<dd>This is a free-function that uses reflection to check if the entity has the required mixins (components) and then operates on them.</dd>
</dl>
<p>To reproduce ECS:</p>
<ol>
<li>Instantiate an empty object (the <strong>Entity</strong>).</li>
<li>Instantiate the stateful objects (the <strong>Components</strong>).</li>
<li>Use reflection to mix-in the components into the entity object.</li>
<li>Pass the entity object to free functions that can operate on objects possessing the mixins (the <strong>System</strong>).</li>
</ol>
<p>This is, in effect, ECS but represented entirely by native language features.</p>
<h3 id="mixins-aren’t-strictly-required">Mixins Aren’t Strictly Required<a href="#mixins-aren’t-strictly-required">#</a></h3>
<p>It’s important to clarify that mixins are not strictly required to achieve this.
You might prefer <em>not</em> to use mixins if, depending on the programming language, their members occupy the same namespace as the entity object and risk naming conflicts with other component members or existing object fields.
In this case, you could rely solely on reflection:</p>
<p>To reproduce ECS without mixins:</p>
<ol>
<li>Instantiate an empty object (the <strong>Entity</strong>).</li>
<li>Instantiate the stateful objects (the <strong>Components</strong>).</li>
<li>Use reflection to inject the components as <em>distinct fields</em> onto the entity object.</li>
<li>Pass the entity object to free functions that can operate on objects possessing the fields (the <strong>System</strong>).</li>
</ol>
<h2 id="the-“rediscovery”-by-game-developers">The “Rediscovery” by Game Developers<a href="#the-“rediscovery”-by-game-developers">#</a></h2>
<p>If mixins and reflection have existed for decades, why is ECS often presented as an innovation, popularized by game developers?</p>
<p>In my opinion, the answer lies in the constraints of statically typed languages, which dominate the game industry.
While incredibly powerful for performance, languages like C++ inherently lack the built-in runtime dynamism, flexible reflection, and mixin capabilities found in languages like Ruby or Lua.</p>
<p>Thus, ECS emerged as a pragmatic and highly effective design pattern to mimic these dynamic, compositional capabilities within a more rigid, compiled environment.
It’s an architectural solution that allows C++ programmers to achieve the same kind of runtime flexibility that is often a native feature in other languages, while simultaneously offering superior control over data layout for performance.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>I sometimes see “ECS frameworks” being announced for programming languages that already possess the inherent dynamism and reflective capabilities that ECS simulates.
Hopefully, this exploration of ECS offers a new perspective.
It’s a testament to clever design and engineering that a pattern can effectively bring the benefits of one paradigm into the ecosystem of another, proving that sometimes, the “new” is simply a brilliant re-invention of the familiar.</p>]]></content>
        </entry>
    
        <entry>
            <title>Drawing: My Five-Month Progression</title>
            <link>https://hgs3.me//journal/drawing-my-five-month-progression</link>
            <updated>Thu, 15 May 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Over the past five months, I’ve been attending studio drawing classes twice a week.
The classes focused on still life drawing and introduced various techniques, including cross contouring and shading.</p>
<p>Most of the art I create on my own is digital, especially vector art.
I enjoy vector art because I can create shapes <em>exactly</em> the way I imagine them.
While I don’t do much hand drawing, I believe improving that skill strengthens my overall artistic ability.</p>
<h2 id="early-semester-work">Early Semester Work<a href="#early-semester-work">#</a></h2>
<p>At the beginning of the semester, we worked with hard and compressed charcoal sticks.
Charcoal creates much deeper, bolder shades than pencil does.</p>
<p>This was my first time using charcoal.
They feel less precise than a pencil, but that might be due to my inexperience.</p>
<figure>
<img alt="First Sketch." height="1218" loading="lazy" src="/assets/sketch.png" width="1200"/>
<figcaption>First sketch: made with hard and compressed charcoal sticks.</figcaption>
</figure>
<h2 id="mid-semester-work">Mid-Semester Work<a href="#mid-semester-work">#</a></h2>
<p>Mid-semester we explored <strong>cross contouring</strong>.
Cross contouring is a technique focused on drawing wireframe-like lines that wrap around forms to express three-dimensionality.
The goal is to capture the shape and volume of the object, not just its outline.</p>
<p>I had never heard of cross contouring before this course, but it quickly became my favorite exercise.
Emphasizing structure and spatial depth helped me make a noticeable leap forward in my skills.</p>
<figure>
<img alt="Mid-Semster Contouring." height="1423" loading="lazy" src="/assets/art-half-progress.png" width="1763"/>
<figcaption>Cross Contouring.</figcaption>
</figure>
<h2 id="final-project">Final Project<a href="#final-project">#</a></h2>
<p>For the final project, we combined everything we had learned into one complete still life drawing.</p>
<figure>
<img alt="Final Sketch." height="1801" loading="lazy" src="/assets/art-progress.png" width="1331"/>
<figcaption>Final sketch: with pencils.</figcaption>
</figure>
<h2 id="everybody-can-draw">Everybody Can Draw<a href="#everybody-can-draw">#</a></h2>
<p>One of the most quietly discouraging things I encountered growing up was hearing people say things like, “I’m a <em>so and so</em> and therefore I can’t draw” where <em>so and so</em> could be math instructor, accountant, doctor, etc.
These kinds of statements, especially from authority figures, made me falsely believe that drawing required some kind of innate talent.</p>
<p>But that’s simply not true.</p>
<p>Drawing is a learned skill, like playing a musical instrument.
It takes study, repetition, and practice just like anything else.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>If you’re considering a drawing course, I highly recommend choosing one with <strong>longer class sessions</strong> rather than one that meets more frequently but for shorter periods.
When you’re drawing, time flies and those extended hours help you settle into the work and produce something consistent.</p>]]></content>
        </entry>
    
        <entry>
            <title>Root Beer: An Ode to my Favorite Soda</title>
            <link>https://hgs3.me//journal/root-beer-an-ode-to-my-favorite-soda</link>
            <updated>Thu, 01 May 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Root Beer is a North American carbonated soda drink.
It’s also my <em>personal favorite</em> soda drink.</p>
<p>I’m not a big soda drinker.
If I’m presented with a choice of generic sodas, I usually prefer water, but root beer is the one soda I never pass up.</p>
<h2 id="origins">Origins<a href="#origins">#</a></h2>
<p>Root Beer has its roots (pun intended) in pre-colonial Indigenous American and early settler traditions.
Indigenous peoples of North America brewed medicinal and ceremonial teas from roots, barks, and herbs.
These mixtures were used to treat ailments, promote health, or for ritual purposes.
While they weren’t carbonated or sweetened like modern soda, they laid the botanical foundation for what would become Root Beer.</p>
<p>In the 17th and 18th centuries, European settlers adopted these traditions, brewing low-alcohol fermented drinks flavored with local roots and herbs.
These beverages were often safer than water and considered nutritious.
Over time, these homemade tonics evolved—especially with the rise of American patent medicines and soft drinks in the 19th century.
What began as herbal brews turned into sweetened, carbonated, commercially bottled Root Beer.</p>
<h2 id="a-natural-soda">A Natural Soda<a href="#a-natural-soda">#</a></h2>
<p>Root Beer is one of the <em>oldest</em> sodas, second only to Ginger Ale and Sarsaparilla.
It can be brewed entirely from naturally occuring ingredents.
Its distinctive flavor comes from the combination of natural herbs and spices, such as:</p>
<ul>
<li>Sassafras root</li>
<li>Sarsaparilla</li>
<li>Birch bark</li>
<li>Wintergreen</li>
<li>Licorice root</li>
<li>Spices like cloves or anise</li>
</ul>
<p>Its one of the few sodas that can be produced in your home kitchen!</p>
<h2 id="an-open-source-soda">An Open Source Soda<a href="#an-open-source-soda">#</a></h2>
<p>Root Beer isn’t “owned” by anyone, unlike brand-name sodas like Pepsi, Dr Pepper, or Sprite.
There’s no single recipe, like there is for Coca-Cola.
Anyone can make their own version.</p>
<p>This freedom has given rise to many variations, from home brews to commercial brands.
In North America, you’re probably familiar with the mainstream A&amp;W, Mug, and Barq’s.</p>
<p>Each variation of Root Beer gets its unique flavor from the specific mix of herbs and spices.
The method of carbonation, whether by machine or natural fermentation, affects the texture and “head” of the drink.</p>
<h2 id="my-collection">My Collection<a href="#my-collection">#</a></h2>
<p>As of this writing, I have <strong>64 bottles</strong> in my Root Beer bottle collection.</p>
<p><img alt="A handful of bottles from my Root Beer bottle collection." src="/assets/root-beer-sample.png"/></p>
<p>Whenever I try a new Root Beer, I record my impressions.
I plan to post reviews of each one in future blog entries.
Stay tuned!</p>]]></content>
        </entry>
    
        <entry>
            <title>Reflecting on Confetti: Now In Beta</title>
            <link>https://hgs3.me//journal/reflecting-on-confetti-now-in-beta</link>
            <updated>Mon, 14 Apr 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Four weeks ago, I announced <a href="https://confetti.hgs3.me/">Confetti</a> on this blog.
Two weeks ago, I shared the project on Reddit and Hacker News to gather feedback.
Today, with the release of <strong>Confetti 1.0 beta</strong>, I’d like to reflect on what I’ve learned, the feedback I received, and where the project goes from here.</p>
<h2 id="initial-reception">Initial Reception<a href="#initial-reception">#</a></h2>
<p>The initial feedback on Reddit was largely positive.
Responses came in quickly and continued for several days.</p>
<p>Hacker News, however, was silent: no comments, no votes, nothing.
I figured maybe I posted at an off time or there just wasn’t interest.
But — a few days later — I woke up to find my post on the <strong>front page</strong>!</p>
<p>It turns out Hacker News has a <a href="https://news.ycombinator.com/item?id=26998309">second-chance pool</a> where moderators can manually boost promising projects that did not receive enough initial attention.
I have no insight into this process or who the moderator was who surfaced Confetti, but if you’re reading this: thank you.</p>
<p>Since sharing the project on social media, <a href="https://github.com/hgs3/confetti/">Confetti’s GitHub repository</a> has seen a surprising amount of traffic, suggesting ongoing interest.</p>
<h2 id="comparisons-with-json">Comparisons with JSON<a href="#comparisons-with-json">#</a></h2>
<p>Several users compared Confetti to JSON.
The comparison mainly revolved around typing: JSON has it, Confetti doesn’t.</p>
<p>JSON offers five built-in types: booleans, numbers, strings, arrays, and objects — plus the special value null.
Confetti, by contrast, is typeless: it operates using strings and directives.</p>
<h3 id="types-vs-typeless">Types vs Typeless<a href="#types-vs-typeless">#</a></h3>
<p>I find the comparison with JSON interesting because, in practice, JSON’s typing doesn’t do as much as often implied:</p>
<p>Firstly, JSON lacks a schema language.
Schema validation is the responsibility of the user application.
Whether you expect an array, object, or a particular element type, you still have to validate it manually — just as you would with Confetti.</p>
<p>Secondly, when validating strings, you sometimes need to go further.
For example, checking if a string is a valid ISO 8601 or RFC 3339 timestamp requires manual validation — just as it would with Confetti.</p>
<p>Lastly, when dealing with numbers, checking if a value is a number in Confetti is as easy as comparing it against a simple regular expression.
And for booleans and null, these are just strings — “true”, “false”, and “null” — and can be verified with a simple string comparison.</p>
<p>So, in my view, JSON’s minimal typing doesn’t add much in real-world use cases.
If you <em>are</em> looking for real, schema-enforced types, then you might consider languages like <a href="https://pkl-lang.org/">Pkl</a> that support user-defined types and structural validation.</p>
<h2 id="feature-suggestions">Feature Suggestions<a href="#feature-suggestions">#</a></h2>
<p>Alongside the initial feedback, I received some thoughtful feature suggestions.
Here are a few that stood out:</p>
<h3 id="bracket-syntax">Bracket Syntax<a href="#bracket-syntax">#</a></h3>
<p>One suggestion was to use brackets to denote multi-line directives.</p>
<p>Right now, you’d use a trailing backslash:</p>
<div class="codehilite"><pre><span></span><code>foo bar \
  baz qux
</code></pre></div>
<p>The proposed alternative uses brackets:</p>
<div class="codehilite"><pre><span></span><code>foo [bar
  baz qux]
</code></pre></div>
<p>I found this suggestion interesting because the syntax resembles an array (minus the commas) as written in various programming languages.
It might even feel more intuitive for long directives that represent list-like concepts.
However, as interesting as the suggestion is, subdirectives can also be used to represent list-likes:</p>
<div class="codehilite"><pre><span></span><code>foo { bar
  baz qux }
</code></pre></div>
<p>Here, an application would treat the subdirectives and their arguments as entries in the “list”.
So, while the “array”-like syntax is interesting, I don’t feel the need to implement it.</p>
<h3 id="execution-model">Execution Model<a href="#execution-model">#</a></h3>
<p>Another suggestion was to give Confetti an execution model — essentially turning it into a programming language.
While intriguing, this is beyond the scope of what I intended for the language.</p>
<p>Confetti is, and will remain, a configuration language.
Its syntax is flexible enough to support domain-specific languages (as shown on the <a href="https://confetti.hgs3.me/examples/#_domain_specific_languages">examples page</a>), but embedding an execution model would go beyond its design goals.</p>
<h2 id="discovering-prior-art">Discovering Prior Art<a href="#discovering-prior-art">#</a></h2>
<p>On the <a href="https://confetti.hgs3.me/">Confetti homepage</a>, I compared Confetti to well-known configuration and data-interchange formats like XML, JSON, INI, and TOML.
After launching, several users pointed out other configuration languages that resemble Confetti syntax.
I’ll briefly discuss them:</p>
<h3 id="sdlang">SDLang<a href="#sdlang">#</a></h3>
<p><a href="https://sdlang.org/">Simple Declarative Language</a>, or SDLang, has some syntactic overlap with Confetti, but goes further than Confetti by adding types for strings, numbers, boolean and null, data/time formats, and binary data.
While they might share some syntactic similarity, SDLang is clearly closer to JSON or TOML than it is to Confetti.</p>
<h3 id="kdl">KDL<a href="#kdl">#</a></h3>
<p><a href="https://kdl.dev/">KDL</a> also has a surface-level similarity with Confetti, but again, it supports types and even allows type annotations.
It, too, is closer to JSON or TOML.</p>
<h3 id="tcl">Tcl<a href="#tcl">#</a></h3>
<p><a href="https://www.tcl-lang.org/">Tcl</a> is a dynamic programming language with a syntax that vaguely resembles Confetti.
However, it’s a full-fledged language with dynamic typing and an execution model.
If you like Confetti but need built-in types and evaluation, Tcl — or Lua — might be worth exploring.</p>
<h2 id="tentative-plans">Tentative Plans<a href="#tentative-plans">#</a></h2>
<p>As of this writing, Confetti is “done.”
Both the C implementation and the specification are in <strong>1.0 beta</strong> status.</p>
<p>My plan is to let the language “bake” in real-world usage for a while.
Depending on how things go, I might increment the version to <strong>1.0 release candidate</strong> in the coming weeks or months, and eventually tag a stable <strong>1.0</strong>.</p>
<h3 id="language-ports">Language Ports<a href="#language-ports">#</a></h3>
<p>The current, canonical implementation of Confetti is implemented in C11.
I originally intended to write a Python and Go port of Confetti, but I don’t personally have a need for them right now.
Authoring them would be mostly for the benefit of others.</p>
<p>With that said, <a href="https://confetti.hgs3.me/specification/">the specification</a> is complete and simple enough that anyone could write a port fairly easily.
If you do, I’d love to hear about it!</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>The positive reception to Confetti has exceeded what I imagined.
I’ll continue to support Confetti for the foreseeable future.
If you find bugs in the specification or implementation, please report them on the project’s <a href="https://github.com/hgs3/confetti/issues">issue tracker</a>.</p>]]></content>
        </entry>
    
        <entry>
            <title>Confetti: The Configuration Language For Humans</title>
            <link>https://hgs3.me//journal/confetti-the-configuration-language-for-humans</link>
            <updated>Fri, 14 Mar 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Today, I’m announcing <strong>Confetti</strong> - a modern configuration language format intended for human editable configuration files.
Checkout its <a href="https://confetti.hgs3.me/">official webpage</a> for examples.</p>
<h2 id="why?">Why?<a href="#why?">#</a></h2>
<p>Formats like XML and JSON are <strong>data-interchange formats</strong>.
They are not great as configuration file formats as the signal to noise ratio is too high.
A missing comma or missing colon can throw everything off.
JSON, in particular, doesn’t even allow comments!</p>
<p>The biggest downside of these formats is they aren’t localization friendly.
Formats, like JSON, require the English words <code>null</code>, <code>true</code>, and <code>false</code>, and Western digits <code>0</code> through <code>9</code>.</p>
<p>Confetti is different.
Confetti lets you write configuration files in your native language.
It’s typeless and doesn’t make assumptions.
For example, you can decide whether <code>true</code>, <code>yes</code>, or <code>on</code> makes the most sense for your application.</p>
<h2 id="minimalistic-design">Minimalistic Design<a href="#minimalistic-design">#</a></h2>
<p>Confetti syntax is loosely inspired by Unix configuration files, the shell word splitting algorithm, and JSON.
I wanted the format to remain <em>typeless</em> and support hierarchical structures.</p>
<p>I designed Confetti to be extensible.
Just like how John Grubber defined Common Markdown and others have created their own Markdown flavors, I encourage others to create their own Confetti flavors.</p>
<h2 id="reference-implementation">Reference Implementation<a href="#reference-implementation">#</a></h2>
<p>I’ve written an implementation of a Confetti parser in C and its source code is <a href="https://github.com/hgs3/confetti/">hosted on GitHub</a>.
This implementation parses Confetti source <em>incrementally</em>.
It does <strong>not</strong> build an in-memory tree-representation like most XML and JSON parsers.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>I have zero expectations for Confetti.
Existing formats, even with their faults, are entrenched in the software ecosystem.
Nonetheless, I created Confetti because I believe it addresses real problems and I hope others will see that too.</p>]]></content>
        </entry>
    
        <entry>
            <title>Railgun Labs: From Vision to Reality</title>
            <link>https://hgs3.me//journal/railgun-labs-from-vision-to-reality</link>
            <updated>Fri, 07 Mar 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p><a href="https://railgunlabs.com/">Railgun Labs</a> is an independent software company founded by myself in 2024.
At the time of this writing, I’ve shipped <strong>five</strong> software products with more on the way.
The company represents the culmination of several years of work and, given that this is my <em>personal</em> website, I wanted to share some of the history and philosophy behind the company.</p>
<h2 id="products-first,-business-second">Products First, Business Second<a href="#products-first,-business-second">#</a></h2>
<p>I’m a passion-driven software developer so I pick projects that I think are “interesting” rather than what will maximize profits.
Put another way, I’m a product guy first and foremost.
I love to build things.
To me, money is a tool at best and an obstacle at worst.</p>
<p>My business strategy is to create products that <em>I</em> think are interesting because if <em>I</em> have a use for them, then I believe <em>others</em> will too.
I understand this approach might yield fewer sales, so I keep my expenditures low.
I view it as an acceptable tradeoff as it allows me to feel more connected to my work.</p>
<h2 id="naming-the-company">Naming the Company<a href="#naming-the-company">#</a></h2>
<p>I named the company “Railgun” after my favorite gun from <a href="https://en.wikipedia.org/wiki/Quake_II">Quake II</a>.
I grew up playing old-school first person shooters and the railgun always stood out as a unique weapon to me.</p>
<p>I added “Labs” after my love of early Hollywood Mad Scientist tropes (see the original Dr. Frankenstein in the 1931 movie “Frankenstein”).</p>
<figure>
<img alt="Dr. Frankenstein’s Lab (1931)." height="431" loading="lazy" src="/assets/frankenstein-lab.png" width="560"/>
<figcaption>Dr. Frankenstein’s Lab as seen in the film Frankenstein (1931).</figcaption>
</figure>
<p>As a name, I think “Railgun Labs” is fun!
It conveys high velocity with experimentation which, I think, is perfect for a small scrappy tech startup.</p>
<h2 id="designing-the-website">Designing the Website<a href="#designing-the-website">#</a></h2>
<p>When designing the company website, I wanted to balance fun with professionalism.
I opted for a minimalistic, flat art style to give that <em>professional</em> feel.
I injected “fun” by choosing vibrant colors.</p>
<h3 id="early-designs">Early Designs<a href="#early-designs">#</a></h3>
<p>I was initially conflicted on how to create the balance I was looking for.
My early designs, I think, went a touch too far:</p>
<figure>
<img alt="Early website design." height="549" loading="lazy" src="/assets/early-railgun-website.png" width="964"/>
<figcaption>Early website design.</figcaption>
</figure>
<p>In this early design, I had mostly finalized the home page layout and logo design, but the colors scheme was completely different from the final version.
In the final design, the colors are <em>vibrant</em> and <em>professional</em> and there’s a bit more humor injected.
For example, the “goto” in “GOTO Products” is a reference to the <a href="https://en.wikipedia.org/wiki/Goto">goto statement</a>.</p>
<figure>
<img alt="Final company website design." height="988" loading="lazy" src="/assets/final-railgun-website.png" width="1403"/>
<figcaption>Final company website design.</figcaption>
</figure>
<p>Websites are always an ongoing project.
I anticipate that I will refresh the design from time-to-time.</p>
<h3 id="designing-a-mascot">Designing a Mascot<a href="#designing-a-mascot">#</a></h3>
<p>Not too many tech companies have a mascot.
The choice to have one was motivated by my desire to create a strong brand identity as well as a sense of playfulness.</p>
<p>The mascot was initially based on the appearance of Doctor Tomoe from the anime <em>Sailor Moon</em>.
I wasn’t too big of an anime fan when I was younger.
My viewing was limited to Pokémon and whatever aired on Toonami, but the design of Doctor Tomoe always stuck with me.</p>
<figure>
<img alt="Doctor Tomoe." height="333" loading="lazy" src="/assets/tomoe.jpg" width="394"/>
<figcaption>Doctor Tomoe.</figcaption>
</figure>
<p>My initial design of the mascot was very reminiscent of Doctor Tomoe.
I think the influence is fairly obvious, once pointed out.</p>
<figure>
<img alt="Early mascot design." height="441" loading="lazy" src="/assets/early-mascot-design.png" width="335"/>
<figcaption>Early mascot design.</figcaption>
</figure>
<p>As I iterated on the design, I toned it down, along with the website, to present the more professional look I was after.
As I approached the final design, I gave the mascot a name: <strong>Dr. Chip Codewell</strong>.
He represents my commitment to innovation.</p>
<figure>
<img alt="Final mascot design." height="383" loading="lazy" src="/assets/final-mascot-design.png" width="260"/>
<figcaption>Final mascot design.</figcaption>
</figure>
<p>Like the website, I expect Chip to continue to undergo refreshes from time-to-time.</p>
<h2 id="product-pricing">Product Pricing<a href="#product-pricing">#</a></h2>
<p>When it comes to pricing my products and services, I wish I could say there was some master strategy or scientific equation I used, but I mostly just reviewed what competitors in the same space were offering and based my prices on theirs.
I also gauged how “expensive” it would be to replicate my work and set my prices lower to make my offerings more appealing.</p>
<h2 id="marketing">Marketing<a href="#marketing">#</a></h2>
<p>I’m not a big social media person, but for marketing I’m relying on it.
I am tentatively planning to attend various, in-person venues in the future.
And my direct outreach to various tech companies has begun.</p>
<p>My <a href="https://news.ycombinator.com/item?id=42423988">post announcing Unicorn</a> reached the front page of Hacker News.
I attribute the success to <em>when</em> I posted: I made the announcement early-mid December when, I think, a non-negligible amount of people were out on vacation for the Holidays and new content was slow thereby making it “easier” for me to get noticed.</p>
<h2 id="an-ongoing-adventure">An Ongoing Adventure<a href="#an-ongoing-adventure">#</a></h2>
<p>Railgun Labs is an ongoing venture for me.
I’m not sure where it will lead, but I don’t regret the decision to quit my job to pursue it.
I plan to continue posting meta updates here as well as other insights as I continue this journey.</p>]]></content>
        </entry>
    
        <entry>
            <title>Hello, World!</title>
            <link>https://hgs3.me//journal/hello-world</link>
            <updated>Sat, 01 Mar 2025 00:00:00 </updated>
            <content type="html"><![CDATA[<p>Hello, everyone!
I’m Henry and this is my personal website.
I decided to create a personal website to collect my work, writing and thoughts in a common place.
I <em>could</em> spend the remainder of this post introducing myself, but I think my <a href="/about">about page</a> does a good job of that.</p>
<h2 id="goals-for-this-website">Goals for this Website<a href="#goals-for-this-website">#</a></h2>
<p>My intentions are to write about my personal projects, thoughts on technology, and my other hobbies (movies, games, music, etc).
I started my own independent software company not too long ago so I intend to share my experience as a budding technopreneur.</p>
<h2 id="subscribe-for-updates">Subscribe for Updates<a href="#subscribe-for-updates">#</a></h2>
<p>I’m not a fan of centralization, much less so when it comes to online communication.
You won’t find me on X or Bluesky.
If you’re interested in following my progress, you can subscribe with your RSS or Atom reader of choice.</p>
<h2 id="closing-thoughts">Closing Thoughts<a href="#closing-thoughts">#</a></h2>
<p>I am not a chronically online person and I avoid traditional social media.
I don’t consume news or much media outside of my interests.
As a result, you might find my perspectives a bit outside the norm.
Nonetheless, I hope you’ll find my writings, at the very least, amusing.</p>]]></content>
        </entry>
    
</feed>