<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.christianbaum.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.christianbaum.com/" rel="alternate" type="text/html" /><updated>2026-04-09T00:03:02-07:00</updated><id>https://www.christianbaum.com/feed.xml</id><title type="html">Christian Michael Baum</title><subtitle>programmer, improviser, and runner who loves the world</subtitle><entry><title type="html">Why Christianbaum Dot Com</title><link href="https://www.christianbaum.com/blog/2026-03-25-why-christianbaum-com" rel="alternate" type="text/html" title="Why Christianbaum Dot Com" /><published>2026-03-25T04:30:00-07:00</published><updated>2026-03-25T04:30:00-07:00</updated><id>https://www.christianbaum.com/blog/why-christianbaum-dot-com</id><content type="html" xml:base="https://www.christianbaum.com/blog/2026-03-25-why-christianbaum-com"><![CDATA[<p>My whole life, I was a huge fan of the “.org” TLD. I also like going by my full name (first, middle last). So, why did I choose “christianbaum.com”?</p>

<p>Honestly, it’s because one of my friends in high school used to call me that. I’ve always been a nerd, so it fits. Otherwise, I’d probably have something like christianmichaelbaum.org. Sometimes, when I type in think about typing on this here, I kind of miss their enthusiastic “Christian baum dot com!”</p>]]></content><author><name></name></author><summary type="html"><![CDATA[My whole life, I was a huge fan of the “.org” TLD. I also like going by my full name (first, middle last). So, why did I choose “christianbaum.com”?]]></summary></entry><entry><title type="html">Blurring the lines of modular monoliths and microservices in .NET with preprocessor directives</title><link href="https://www.christianbaum.com/blog/2025-08-29-modular-monolith-1" rel="alternate" type="text/html" title="Blurring the lines of modular monoliths and microservices in .NET with preprocessor directives" /><published>2025-08-29T00:46:00-07:00</published><updated>2025-08-29T00:46:00-07:00</updated><id>https://www.christianbaum.com/blog/modular-monolth-1</id><content type="html" xml:base="https://www.christianbaum.com/blog/2025-08-29-modular-monolith-1"><![CDATA[<p>This is an exploration of the idea of having both a modular monolith and microservice architecture; the possibility of splitting the deployments up for the purpose of scaling with little compromise. Using directives, build configurations, and some smart architectural patterns, you can setup your deployables to one, or more depending on your needs. This is simply a “how to”, and I’m not engaging into the “why” on modular monoliths or microservices. With this configuration, you don’t need to engage one way or the other because you can have both! Sometimes, it pays to be indecivive.</p>

<p>If you plan on sticking to a modular monolith and never ever want to scale out, this may not be for you. But what if you need the benefits of microservices? You wouldn’t want to deploy your entire 100 service application just to scale one service.</p>

<p>Before you get too eager to adopt this pattern, I must warn: it is another vector for potential bugs. –That’s why I’m planning on writing what you see here into a library with source generation and possibly a dotnet tool, as– I see the potential, but we’re not quite there <em>yet</em>.</p>

<h2 id="setting-it-all-up">Setting it all up</h2>

<p>Our project setup is pretty standard modular monolith stuff:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>src/
├─ host/
│  ├─ Domain.Host.Web/
│  │  ├─ Program.cs
│  │  ├─ Domain.Host.Web.csproj
├─ product/
│  ├─ Domain.Product/
│  │  ├─ SomeCode.cs
│  │  ├─ Domain.Host.csproj
├─ customer/
│  ├─ Domain.Customer/
│  │  ├─ SomeMoreCode.cs
│  │  ├─ Domain.Customer.csproj
├─ Domain.sln
├─ Domain.slnx 
</code></pre></div></div>

<p>We have 3 projects: 1 Project is Domain.Host, which is our entrypoint. For each build configuration, we’re including different project references. <em>Debug</em> and <em>Release</em> builds the monolith, so all projects are included, while the four other configurations only reference their respective projects.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Project</span> <span class="na">Sdk=</span><span class="s">"Microsoft.NET.Sdk.Web"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;PropertyGroup&gt;</span>
    <span class="nt">&lt;TargetFramework&gt;</span>net8.0<span class="nt">&lt;/TargetFramework&gt;</span>
    <span class="nt">&lt;Nullable&gt;</span>enable<span class="nt">&lt;/Nullable&gt;</span>
    <span class="nt">&lt;ImplicitUsings&gt;</span>enable<span class="nt">&lt;/ImplicitUsings&gt;</span>
  <span class="nt">&lt;/PropertyGroup&gt;</span>
  <span class="nt">&lt;ItemGroup</span> <span class="na">Condition=</span><span class="s">"'$(Configuration)' == 'Debug' Or '$(Configuration)' == 'Release'"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;ProjectReference</span> <span class="na">Include=</span><span class="s">"..\..\customer\Domain.Customer\Domain.Customer.csproj"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;ProjectReference</span> <span class="na">Include=</span><span class="s">"..\..\product\Domain.Product\Domain.Product.csproj"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>
  <span class="nt">&lt;ItemGroup</span> <span class="na">Condition=</span><span class="s">"'$(Configuration)' == 'Debug Customer' Or '$(Configuration)' == 'Release Customer'"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;ProjectReference</span> <span class="na">Include=</span><span class="s">"..\..\customer\Domain.Customer\Domain.Customer.csproj"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>
  <span class="nt">&lt;ItemGroup</span> <span class="na">Condition=</span><span class="s">"'$(Configuration)' == 'Debug Product' Or '$(Configuration)' == 'Release Product'"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;ProjectReference</span> <span class="na">Include=</span><span class="s">"..\..\product\Domain.Product\Domain.Product.csproj"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/ItemGroup&gt;</span>
<span class="nt">&lt;/Project&gt;</span>
</code></pre></div></div>

<p>You’ll need to specify the configurations in the sln/slnx file. The sln file is quite ugly so I’m not going to bother sharing what that looks like. Instead, I’ll show what my slnx file looks like. You’ll notice each project shows which configurations are being built. All projects are built when building for Debug or Release, while Domain.Customer.csproj doesn’t include the BuildType <em>Debug Product</em>/<em>Release Product</em>, and Domain.Product.csproj doesn’t include the BuildType for <em>Debug Customer</em>/<em>Release Customer</em>.</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Solution&gt;</span>
 <span class="nt">&lt;Configurations&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Debug Customer"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Debug Product"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Release Customer"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;BuildType</span> <span class="na">Name=</span><span class="s">"Release Product"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Platform</span> <span class="na">Name=</span><span class="s">"Any CPU"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Platform</span> <span class="na">Name=</span><span class="s">"x64"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;Platform</span> <span class="na">Name=</span><span class="s">"x86"</span> <span class="nt">/&gt;</span>
  <span class="nt">&lt;/Configurations&gt;</span>
  <span class="nt">&lt;Folder</span> <span class="na">Name=</span><span class="s">"src"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Folder</span> <span class="na">Name=</span><span class="s">"host"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;Project</span> <span class="na">Path=</span><span class="s">"src/host/Domain.Host/Domain.Host.csproj"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug Customer|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug Product|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release Customer|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release Product|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/Project&gt;</span>
    <span class="nt">&lt;Project</span> <span class="na">Path=</span><span class="s">"src/customer/Domain.Customer/Domain.Customer.csproj"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug Customer|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release Customer|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/Project&gt;</span>
    <span class="nt">&lt;Project</span> <span class="na">Path=</span><span class="s">"src/product/Domain.Product/Domain.Product.csproj"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Debug Product|*"</span> <span class="na">Project=</span><span class="s">"Debug"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
      <span class="nt">&lt;BuildType</span> <span class="na">Solution=</span><span class="s">"Release Product|*"</span> <span class="na">Project=</span><span class="s">"Release"</span> <span class="nt">/&gt;</span>
    <span class="nt">&lt;/Project&gt;</span>
  <span class="nt">&lt;/Folder&gt;</span>
<span class="nt">&lt;/Solution&gt;</span>
</code></pre></div></div>

<p>The magic happens inside of Program.cs. There will be five sections in our file.</p>

<ol>
  <li>Defining the services</li>
  <li>Defining features</li>
  <li>The using statements</li>
  <li>The app initialization</li>
  <li>App configuration</li>
</ol>

<p>The first two sections simply use preprocessor directives to define the services and needed features of the services. <em>DEBUG_CUSTOMER</em> should be defined if the configuration is <em>Debug Customer</em>. We’ll use preprocessor directives later to define features and initialize our services. We’ll pretend that our services have slightly different needs, like the Customer service might use MassTransit while the Product service doesn’t, but it needs views. It’s okay, for example, that <em>ENTITY_FRAMEWORK_CORE</em> is defined twice. This is to ensure our features are only initialized once to prevent bugs. It’s important to keep track of which apps use which features.</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#region Define services
#if DEBUG_CUSTOMER || RELEASE_CUSTOMER || DEBUG || RELEASE
#define CUSTOMER_SERVICE
#endif
</span>
<span class="cp">#if DEBUG_PRODUCT || RELEASE_PRODUCT || DEBUG || RELEASE
#define PRODUCT_SERVICE
#endif
#endregion
</span>
<span class="cp">#region Defining features
#if CUSTOMER_SERVICE
#define ENTITY_FRAMEWORK_CORE
#define MASSTRANSIT
#define ROUTING
#define AUTHORIZATION
#define CONTROLLERS
#endif
</span>
<span class="cp">#if PRODUCT_SERVICE
#define ENTITY_FRAMEWORK_CORE
#define ROUTING
#define AUTHORIZATION
#define CONTROLLERS_WITH_VIEWS
#endif
#endregion
</span></code></pre></div></div>

<p>In the third section, you can start to see why we needed to define services and features separately. We’re surrounding our using statements with these preprocessor directives. If these were lumped together in with the services, we would have gotten the warning CS0105 about duplicate using statements.</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#region Using statements
#if CUSTOMER_SERVICE
</span><span class="k">using</span> <span class="nn">Domain.Custmer</span><span class="p">;</span>
<span class="cp">#endif
#if PRODUCT_SERVICE
</span><span class="k">using</span> <span class="nn">Domain.Product</span><span class="p">;</span>
<span class="cp">#endif
#if MASSTRANSIT
</span><span class="k">using</span> <span class="nn">MassTransit</span><span class="p">;</span>
<span class="cp">#endif
#if ENTITY_FRAMEWORK_CORE
</span><span class="k">using</span> <span class="nn">Microsoft.EntityFrameworkCore</span><span class="p">;</span>
<span class="cp">#endif
#endregion
</span></code></pre></div></div>

<p>Now, it’s time for the app initialization. I do recommend generally separating each line into its own feature. However, and this is important. You’ll have to keep track of which apps use which feature, or you’ll run into problems when you find apps are using features that are not defined.</p>

<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#region App initialization
</span>
<span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">WebApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

<span class="cp">#if ENTITY_FRAMEWORK_CORE
</span>    <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="n">AddDbContextFactory</span><span class="p">&lt;</span><span class="n">DbContext</span><span class="p">&gt;(</span>
        <span class="n">options</span> <span class="p">=&gt;</span> <span class="n">options</span><span class="p">.</span><span class="nf">UseSqlServer</span><span class="p">(</span><span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">.</span><span class="nf">GetConnectionString</span><span class="p">(</span><span class="s">"Domain"</span><span class="p">)!));</span>
<span class="cp">#endif
</span>
<span class="c1">// It can get a bit tricky with cases like this where it's not simply "On" or "Off"</span>
<span class="cp">#if CONTROLLERS_WITH_VIEWS
</span><span class="kt">var</span> <span class="n">mvcBuilder</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddControllersWithViews</span><span class="p">();</span>
<span class="cp">#elif CONTROLLERS
</span><span class="kt">var</span> <span class="n">mvcBuilder</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddControllers</span><span class="p">();</span>
<span class="cp">#endif
</span>
<span class="cp">#if CUSTOMER_SERVICE
</span><span class="c1">// Defined in Domain.Customer</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddCustomerService</span><span class="p">();</span>
<span class="cp">#endif
</span>
<span class="cp">#if PRODUCT_SERVICE
</span><span class="c1">// Defined in Domain.Product</span>
<span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddProductService</span><span class="p">();</span>
<span class="cp">#endif
</span>
<span class="cp">#if MASSTRANSIT
</span><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddMassTransit</span><span class="p">(</span><span class="n">config</span> <span class="p">=&gt;</span>

<span class="cp">#if CUSTOMER_SERVICE
</span>  <span class="c1">// Defined in Domain.Customer</span>
  <span class="n">config</span><span class="p">.</span><span class="nf">AddCustomerServiceConsumers</span><span class="p">();</span>
<span class="cp">#endif
</span>    <span class="c1">// </span>
    <span class="n">config</span><span class="p">.</span><span class="nf">UsingInMemory</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">cfg</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="n">cfg</span><span class="p">.</span><span class="nf">ConfigureEndpoints</span><span class="p">(</span><span class="n">context</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">});</span>
<span class="cp">#endif
#endregion
</span>
<span class="cp">#region App configuration
</span><span class="kt">var</span> <span class="n">app</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>

<span class="cp">#if ROUTING
</span><span class="n">app</span><span class="p">.</span><span class="nf">UseRouting</span><span class="p">();</span>
<span class="cp">#endif 
</span>
<span class="cp">#if AUTHORIZATION
</span><span class="n">app</span><span class="p">.</span><span class="nf">UseAuthorization</span><span class="p">();</span>
<span class="cp">#endif
</span>
<span class="cp">#if CONTROLLERS
</span><span class="c1">// Might not be the best pattern structure for a modular monolith</span>
<span class="n">app</span><span class="p">.</span><span class="nf">MapControllerRoute</span><span class="p">(</span>
    <span class="n">name</span><span class="p">:</span> <span class="s">"default"</span><span class="p">,</span>
    <span class="n">pattern</span><span class="p">:</span> <span class="s">"{controller=Home}/{action=Index}/{id?}"</span><span class="p">);</span>
<span class="cp">#endif
</span>
<span class="cp">#endregion
</span></code></pre></div></div>

<p>That’s about it! Keep your application host program light and you probably won’t be editing it too much except to add new services.</p>

<h2 id="considerations-of-this-approach">Considerations of this approach</h2>

<h3 id="you-really-need-to-keep-track-of-which-services-use-which-features">You really need to keep track of which services use which features</h3>

<p>If you add a feature down the line to a service and it’s defined in another service, it might build fine in modular monolith mode, but fail to build when scaling out a service because the necessary feature wasn’t defined in the app’s feature preprocessor directive. Or worse: it might build, but fail in unexpected ways later.</p>

<h3 id="more-deployables-can-lead-to-more-solution-configurations">More deployables can lead to more solution configurations</h3>

<p>If you plan on using this as an option to deploy many microservices, and you have many projects, you’ll likely have twice as many configurations as services. I’m hopeful with the rise of slnx, this won’t be much of a problem.</p>

<h3 id="designed-with-one-entry-point-in-mind">Designed with one entry point in mind</h3>

<p>If you hope to use something like Azure functions, AWS lambdas, or anything else that controls the entry points, it seems pretty obvious but this is not relevant to that. You’ll still need to create separate a project for each entrypoint in this case. It’s still possible to have a lambda and a modular monolith in the same solution.</p>

<h3 id="horizontal-scaling-is-more-attuned-for-the-message-broker-pattern">Horizontal scaling is more attuned for the message broker pattern</h3>

<p>We use MassTransit which works well for our needs, although I’ve heard good things about other message brokers. Our setup allows us to deploy more or less applications with relative ease. If you’re planning on horizontally scaling your API services, you’ll probably want some load balancers and/or API gateways to distribute the load and route you to the correct app. I have considered that one option would be to put as much of your business logic as you can into a message broker, and your APIs and webpages minimal. You might need more special configurations for your API gateways and load balancers with things like Blazor. We’ve actually moved away from Blazor internally because of its architecture and client/server requirements, such as its sticky session requirement.</p>

<h3 id="final-thoughts">Final thoughts</h3>

<p>I’ve been using this pattern for about 9 months and I’m working out the kinks. I think as it stands, this pattern is a little awkward to use and it is easy to introduce bugs that might not be visible if you’re using one deployable until you start scaling out into multiple deployables. –However, the main reason I think you should wait before implementing this pattern is because I think this pattern has potential as a library using source generation for setting up the and probably a .NET tool for creating different build configurations.– Update: 8/30: I’ve explored this option and currently I think this is the least complicated option.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This is an exploration of the idea of having both a modular monolith and microservice architecture; the possibility of splitting the deployments up for the purpose of scaling with little compromise. Using directives, build configurations, and some smart architectural patterns, you can setup your deployables to one, or more depending on your needs. This is simply a “how to”, and I’m not engaging into the “why” on modular monoliths or microservices. With this configuration, you don’t need to engage one way or the other because you can have both! Sometimes, it pays to be indecivive.]]></summary></entry><entry><title type="html">Accessible sidebar drawer with great UX</title><link href="https://www.christianbaum.com/blog/2024-11-26-accessible-sidebar-drawer-with-great-ux" rel="alternate" type="text/html" title="Accessible sidebar drawer with great UX" /><published>2024-11-26T01:41:39-07:00</published><updated>2024-11-26T01:41:39-07:00</updated><id>https://www.christianbaum.com/blog/accessible-sidebar-drawer-with-great-ux</id><content type="html" xml:base="https://www.christianbaum.com/blog/2024-11-26-accessible-sidebar-drawer-with-great-ux"><![CDATA[<p>If you are on mobile, or if you shrink the window, you’ll see a hamburger menu with a toggleable sidebar. This is functional with javascript disabled, although some javascript was added to enhance the experience. So, how do you implement it?</p>

<p>Start by adding two radio buttons. One for the “on” button, one for “off” button. The label button is a UX trick to dismiss the modal by clicking outside of the menu. Make sure to add the aria-hidden attribute to these so screen readers don’t pick it up. The state of the drawer is kept in these radio buttons.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"radio"</span>
  <span class="na">class=</span><span class="s">"menu-toggle open"</span>
  <span class="na">name=</span><span class="s">"menu-toggle"</span>
  <span class="na">title=</span><span class="s">"Open"</span>
  <span class="na">aria-hidden=</span><span class="s">"true"</span>
  <span class="na">tabindex=</span><span class="s">"-1"</span>
  <span class="na">id=</span><span class="s">"ta_menuOpen"</span><span class="nt">&gt;</span>
<span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">"radio"</span>
  <span class="na">class=</span><span class="s">"menu-toggle close"</span>
  <span class="na">name=</span><span class="s">"menu-toggle"</span>
  <span class="na">title=</span><span class="s">"Close"</span>
  <span class="na">aria-hidden=</span><span class="s">"true"</span>
  <span class="na">id=</span><span class="s">"ta_menuClose"</span>
  <span class="na">tabindex=</span><span class="s">"-1"</span><span class="nt">&gt;</span>
<span class="nt">&lt;label</span> <span class="na">class=</span><span class="s">"menu-toggle overlay hidden"</span>
  <span class="na">for=</span><span class="s">"ta_menuClose"</span>
  <span class="na">tabindex=</span><span class="s">"-1"</span><span class="nt">&gt;&lt;/label&gt;</span>
</code></pre></div></div>

<p>This CSS makes the radio buttons act like a menu toggle in the top right corner. When the menu is open, the z-index of the close button is put to the top. At the same time, the overlay is brought up behind the menu which also acts like a close button. The menu is optimized for right-handed users, which is the majority of the population. Sorry, left-handers!</p>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.menu-toggle</span><span class="o">,</span> <span class="nc">.menu-toggle.overlay</span><span class="o">,</span> <span class="nc">.theme-toggle</span> <span class="p">{</span>
  <span class="nl">position</span><span class="p">:</span> <span class="nb">fixed</span><span class="p">;</span>
  <span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.overlay</span> <span class="p">{</span>
  <span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">right</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="o">,</span> <span class="nc">.menu-toggle.close</span> <span class="p">{</span>
  <span class="nl">width</span><span class="p">:</span> <span class="m">40px</span><span class="p">;</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">40px</span><span class="p">;</span>
  <span class="nl">cursor</span><span class="p">:</span> <span class="nb">pointer</span><span class="p">;</span>
  <span class="nl">top</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
  <span class="nl">right</span><span class="p">:</span> <span class="m">-1px</span><span class="p">;</span>
  <span class="na">-webkit-touch-callout</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">-webkit-user-select</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">-khtml-user-select</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">-moz-user-select</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">-ms-user-select</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">user-select</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
  <span class="na">-webkit-tap-highlight-color</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span> 
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span> <span class="p">{</span>
  <span class="nl">z-index</span><span class="p">:</span> <span class="m">500</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.menu-toggle.close</span> <span class="p">{</span>
  <span class="nl">z-index</span><span class="p">:</span> <span class="m">500</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.out</span> <span class="p">{</span>
  <span class="nl">width</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">100%</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.menu-toggle.overlay</span> <span class="p">{</span>
  <span class="nl">right</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">position</span><span class="p">:</span> <span class="nb">fixed</span><span class="p">;</span>
  <span class="nl">z-index</span><span class="p">:</span> <span class="m">100</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The nav bar is kept to the right of the screen at all times. When the menu bar is toggled, a css selector applies a transform to bring out the navigation drawer with a neat animation using a css transition. Here, I set the animation time to 0.25s which feels appropriate. To the best of my knowledge, the menu must be a sibling of the radio button, but that may not be necessaary with newer combinators I haven’t learned how to fully utilize yet. Something extra I do for my site is I offset the content with as well. This is why I have the radio buttons on the same level as the content. One other thing to note is this sidebar drawer is turned into a topnav with a media query, when the window is greater than 800px.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"nav-bar-container"</span> <span class="na">id=</span><span class="s">"ta_navbarContainer"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;nav</span> <span class="na">class=</span><span class="s">"nav-bar"</span><span class="nt">&gt;</span>
    <span class="c">&lt;!--Nav bar contents--&gt;</span>
  <span class="nt">&lt;/nav&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.nav-bar</span> <span class="nc">.menu</span> <span class="p">{</span>
  <span class="nl">right</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">transform</span><span class="p">:</span> <span class="nf">translateX</span><span class="p">(</span><span class="nv">$nav-bar-width-plus-border</span><span class="p">);</span>
  <span class="nl">transition</span><span class="p">:</span> <span class="n">transform</span> <span class="m">0</span><span class="mi">.25s</span><span class="p">;</span>
  <span class="nl">position</span><span class="p">:</span> <span class="nb">fixed</span><span class="p">;</span>
  <span class="nl">width</span><span class="p">:</span> <span class="nv">$nav-bar-width</span><span class="p">;</span>
  <span class="nl">top</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
  <span class="nl">height</span><span class="p">:</span> <span class="m">100vh</span><span class="p">;</span>
  <span class="nl">padding-top</span><span class="p">:</span> <span class="nv">$nav-bar-height</span><span class="p">;</span>
  <span class="nl">box-shadow</span><span class="p">:</span><span class="m">-4px</span> <span class="m">-4px</span> <span class="m">18px</span> <span class="m">-9px</span> <span class="nf">rgba</span><span class="p">(</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="o">,</span><span class="m">0</span><span class="mi">.77</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.nav-bar-container</span> <span class="nc">.nav-bar</span> <span class="p">{</span>
  <span class="nl">transform</span><span class="p">:</span> <span class="nf">translate</span><span class="p">(</span><span class="m">0</span><span class="o">,</span> <span class="o">-</span><span class="nv">$nav-bar-height-plus-border</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Voila! You should have a functioning drawer!</p>

<h2 id="enhancing-with-vanilla-javascript">Enhancing with vanilla javascript</h2>

<p>While we can definitely call it done here, there’s another user experience trick we can add: gestures. On most of the apps on my phone, the drawer can be opened by swiping the edge of the screen, closed by swiping the drawer closed. This is pretty easy to implement in pure vanilla Javascript. First I’ll paste the code, and then I’ll go over it.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">initDraggableDrawer</span><span class="p">()</span> <span class="p">{</span>
  <span class="kd">const</span> <span class="nx">beginEvents</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">mousedown</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">touchstart</span><span class="dl">"</span><span class="p">];</span>
  <span class="kd">const</span> <span class="nx">releaseEvents</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">mouseup</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">mouseleave</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">touchend</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">touchcancel</span><span class="dl">"</span><span class="p">];</span>
  <span class="kd">const</span> <span class="nx">moveEvents</span> <span class="o">=</span> <span class="p">[</span><span class="dl">"</span><span class="s2">mousemove</span><span class="dl">"</span><span class="p">,</span> <span class="dl">"</span><span class="s2">touchmove</span><span class="dl">"</span><span class="p">];</span>

  <span class="kd">function</span> <span class="nx">addEventListeners</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">events</span><span class="p">,</span> <span class="nx">method</span><span class="p">,</span> <span class="nx">options</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="k">of</span> <span class="nx">events</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">target</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">method</span><span class="p">,</span> <span class="nx">options</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">removeEventListeners</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">events</span><span class="p">,</span> <span class="nx">method</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">for</span><span class="p">(</span><span class="kd">let</span> <span class="nx">i</span> <span class="k">of</span> <span class="nx">events</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">target</span><span class="p">.</span><span class="nx">removeEventListener</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span> <span class="nx">method</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">getEventX</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">targetTouches</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">targetTouches</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">e</span><span class="p">.</span><span class="nx">targetTouches</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">clientX</span><span class="p">;</span>
      <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">lastX</span><span class="p">;</span>
      <span class="p">}</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">return</span> <span class="nx">e</span><span class="p">.</span><span class="nx">clientX</span><span class="p">;</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">getStyleTransformX</span><span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">let</span> <span class="nx">style</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">getComputedStyle</span><span class="p">(</span><span class="nx">menu</span><span class="p">);</span>
    <span class="k">return</span> <span class="k">new</span> <span class="nx">DOMMatrixReadOnly</span><span class="p">(</span><span class="nx">style</span><span class="p">.</span><span class="nx">transform</span><span class="p">).</span><span class="nx">m41</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">updateTransform</span><span class="p">(</span><span class="nx">target</span><span class="p">,</span> <span class="nx">value</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">value</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">value</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="kd">let</span> <span class="nx">style</span> <span class="o">=</span> <span class="nb">window</span><span class="p">.</span><span class="nx">getComputedStyle</span><span class="p">(</span><span class="nx">menu</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">matrix</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">DOMMatrix</span><span class="p">(</span><span class="nx">style</span><span class="p">.</span><span class="nx">transform</span><span class="p">);</span>
    <span class="nx">matrix</span><span class="p">.</span><span class="nx">m41</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
    <span class="nx">target</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">transform</span> <span class="o">=</span> <span class="nx">matrix</span><span class="p">.</span><span class="nx">toString</span><span class="p">();</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">checkForDrawerOpenGesture</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">clientWidth</span> <span class="o">-</span> <span class="nx">getEventX</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">30</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">prepareDrag</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
    <span class="p">}</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">addGestureEventListeners</span><span class="p">()</span> <span class="p">{</span>
    <span class="nx">addEventListeners</span><span class="p">(</span><span class="nx">menu</span><span class="p">,</span> <span class="nx">beginEvents</span><span class="p">,</span> <span class="nx">prepareDrag</span><span class="p">,</span> <span class="p">{</span><span class="na">passive</span><span class="p">:</span> <span class="kc">true</span><span class="p">});</span>
    <span class="nx">addEventListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">beginEvents</span><span class="p">,</span> <span class="nx">checkForDrawerOpenGesture</span><span class="p">,</span> <span class="p">{</span><span class="na">passive</span><span class="p">:</span> <span class="kc">true</span><span class="p">});</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">prepareDrag</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">removeEventListeners</span><span class="p">(</span><span class="nx">menu</span><span class="p">,</span> <span class="nx">beginEvents</span><span class="p">,</span> <span class="nx">prepareDrag</span><span class="p">);</span>
    <span class="nx">removeEventListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">beginEvents</span><span class="p">,</span> <span class="nx">checkForDrawerOpenGesture</span><span class="p">);</span>
    <span class="nx">addEventListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">moveEvents</span><span class="p">,</span> <span class="nx">drag</span><span class="p">,</span> <span class="p">{</span><span class="na">passive</span><span class="p">:</span> <span class="kc">false</span><span class="p">});</span>
    <span class="nx">addEventListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">releaseEvents</span><span class="p">,</span> <span class="nx">release</span><span class="p">,</span> <span class="p">{</span><span class="na">once</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="na">passive</span><span class="p">:</span> <span class="kc">false</span><span class="p">});</span>
    <span class="nx">lastX</span> <span class="o">=</span> <span class="nx">initialX</span> <span class="o">=</span> <span class="nx">getEventX</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
    <span class="nx">transformStart</span> <span class="o">=</span> <span class="nx">getStyleTransformX</span><span class="p">(</span><span class="nx">menu</span><span class="p">);</span>
    <span class="nx">timeStart</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">();</span>
    <span class="nx">dragged</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
    <span class="nx">updateTransform</span><span class="p">(</span><span class="nx">menu</span><span class="p">,</span> <span class="nx">transformStart</span><span class="p">);</span>
    <span class="nx">menu</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">transition</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">none</span><span class="dl">"</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">drag</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">lastX</span> <span class="o">=</span> <span class="nx">getEventX</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
    <span class="kd">let</span> <span class="nx">delta</span> <span class="o">=</span> <span class="nx">initialX</span> <span class="o">-</span> <span class="nx">lastX</span><span class="p">;</span>
    <span class="kd">let</span> <span class="nx">transformCurrent</span> <span class="o">=</span> <span class="nx">transformStart</span> <span class="o">-</span> <span class="nx">delta</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">dragged</span> <span class="o">||</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">abs</span><span class="p">(</span><span class="nx">delta</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">15</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">dragged</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
      <span class="k">if</span><span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">cancelable</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
        <span class="nx">e</span><span class="p">.</span><span class="nx">stopImmediatePropagation</span><span class="p">();</span>
      <span class="p">}</span>
    <span class="p">}</span>
    <span class="nx">updateTransform</span><span class="p">(</span><span class="nx">menu</span><span class="p">,</span> <span class="nx">transformCurrent</span><span class="p">);</span>
  <span class="p">}</span>

  <span class="kd">function</span> <span class="nx">release</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">removeEventListeners</span><span class="p">(</span><span class="nb">document</span><span class="p">,</span> <span class="nx">moveEvents</span><span class="p">,</span> <span class="nx">drag</span><span class="p">)</span>
    <span class="nx">addGestureEventListeners</span><span class="p">();</span>
    <span class="nx">menu</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">transform</span> <span class="o">=</span> <span class="nx">menu</span><span class="p">.</span><span class="nx">style</span><span class="p">.</span><span class="nx">transition</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">dragged</span> <span class="o">&amp;&amp;</span> <span class="nx">e</span><span class="p">.</span><span class="nx">cancelable</span><span class="p">)</span> <span class="p">{</span>
      <span class="nx">e</span><span class="p">.</span><span class="nx">preventDefault</span><span class="p">();</span>
      <span class="nx">e</span><span class="p">.</span><span class="nx">stopImmediatePropagation</span><span class="p">()</span>
    <span class="p">}</span>
    <span class="cm">/* Check that the user didn't potentially tap/click*/</span>
    <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">dragged</span><span class="p">)</span> <span class="k">return</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">timeEnd</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">().</span><span class="nx">getTime</span><span class="p">(),</span>
        <span class="nx">diff</span> <span class="o">=</span> <span class="nx">initialX</span> <span class="o">-</span> <span class="nx">getEventX</span><span class="p">(</span><span class="nx">e</span><span class="p">);</span>
    <span class="c1">// the logic in here is manually tuned for user experience</span>
    <span class="k">if</span><span class="p">(</span> <span class="cm">/* Check if it is over half*/</span>
      <span class="p">((</span><span class="nx">transformStart</span> <span class="o">+</span> <span class="nx">diff</span><span class="p">)</span> <span class="o">&gt;</span> <span class="o">-</span><span class="p">(</span><span class="nx">menu</span><span class="p">.</span><span class="nx">clientWidth</span><span class="o">/</span><span class="mi">2</span><span class="p">))</span> <span class="o">||</span>
        <span class="cm">/* Check if the user pulled fast and it's over 1/8 */</span>
      <span class="p">(</span><span class="nx">timeEnd</span> <span class="o">-</span> <span class="nx">timeStart</span> <span class="o">&lt;</span> <span class="mi">100</span> <span class="cm">/*ms*/</span> <span class="o">&amp;&amp;</span> <span class="nx">diff</span> <span class="o">&gt;</span> <span class="p">(</span><span class="nx">menu</span><span class="p">.</span><span class="nx">clientWidth</span><span class="o">/</span><span class="mi">8</span><span class="p">))</span>
    <span class="p">)</span> <span class="p">{</span>
      <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">"</span><span class="s2">.menu-toggle.open</span><span class="dl">"</span><span class="p">).</span><span class="nx">checked</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="nb">document</span><span class="p">.</span><span class="nx">querySelector</span><span class="p">(</span><span class="dl">"</span><span class="s2">.menu-toggle.close</span><span class="dl">"</span><span class="p">).</span><span class="nx">checked</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
    <span class="p">}</span>
    <span class="nx">initialX</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
  <span class="p">}</span>

  <span class="kd">let</span> <span class="nx">menu</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="dl">"</span><span class="s2">ta_hamburgerMenu</span><span class="dl">"</span><span class="p">),</span>
          <span class="nx">initialX</span><span class="p">,</span> <span class="nx">lastX</span><span class="p">,</span> <span class="nx">transformStart</span><span class="p">,</span> <span class="nx">timeStart</span><span class="p">,</span>
          <span class="nx">dragged</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
  <span class="nx">addGestureEventListeners</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<p>If you look at the bottom of the function, it gets the ta_hamburgerMenu element and calls addGestureEventListeners. The first event listener in addGestureEventListeners adds the event mouseDown and touchStart to the navigation drawer. If it is open, a drag gesture is initiated as long as the mouse is held down. The second event listener calls checkForDrawerOpenGesture, which initiates a drag gesture if the right 30 pixels of the screen were pressed.</p>

<p>Now let’s look at the prepareDrag function. It starts by removing event listeners that were used to. When a drag gesture is finished, those event listeners are added back. This is to prevent this function from being called multiple times without using an extra state boolean. Then, it adds event listeners for dragging and for releasing the drag. Then it keeps track of the initial X position, the start time, and we set the boolean dragged to false, so micro drags caused by taps/clicks are not tracked. Finally, we stop the manual css transform by setting transition to “none” and manually setting the transform. A nice side-effect of this is if you were to release and restart a drag gesture, you can catch the transform mid-transition. That’s why we are getting and setting the css transform manually in the getStyleTransformX and updateTransform functions.  The updateTransform function just does a check to make sure the drawer isn’t dragged beyond its size and then updates the transform css property. The state of the transform is kept in css at all times.</p>

<p>The drag method, which is triggered on touch move or mouse move, does some calculations based on the mouse/touch positions to delta and the beginning of the transformation to determine the current transform position. The only other thing this does, is if the movement is less than 15 pixels, then we don’t consider this a drag gesture at all, tracked by the “dragged” boolean. This is so users don’t click a link, make a micro movement and have their click event cancelled. Finally, the transform is set.</p>

<p>The release method first resets the state by removing the movement event listeners (the release event listener is marked as “once”), adds back the event listeners for preparing a drag event and resets the inline styles for transition and transform. If a drag gesture was detected (at least 15px of movement), it then does a check to see if it should open or close. As noted, the logic was manually tuned: First, if the menu was pulled half-way open, it opens. Likewise, if it is pulled halfway closed, it closes.  The second part of the if statement checks for if the edge of the screen was rapidly swiped open.</p>

<h2 id="bonus-hamburger-icon-with-animation">Bonus: Hamburger icon with animation</h2>

<p>As a bonus, this is my hamburger icon. The three span elements are for a cute css animation. The hamburger icon turns into an X when the menu is toggled.</p>

<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;div</span> <span class="na">class=</span><span class="s">"hamburger semisticky"</span> <span class="na">id=</span><span class="s">"ta_hamburger"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;span&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;span&gt;&lt;/span&gt;</span>
    <span class="nt">&lt;span&gt;&lt;/span&gt;</span>
<span class="nt">&lt;/div&gt;</span>
</code></pre></div></div>

<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.hamburger</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
    <span class="nl">position</span><span class="p">:</span> <span class="nb">absolute</span><span class="p">;</span>
    <span class="nl">right</span><span class="p">:</span> <span class="m">18px</span><span class="p">;</span>
    <span class="nl">top</span><span class="p">:</span> <span class="m">18px</span><span class="p">;</span>
    <span class="nl">z-index</span><span class="p">:</span> <span class="m">400</span><span class="p">;</span>
    <span class="nl">transition</span><span class="p">:</span> <span class="n">transform</span> <span class="m">0</span><span class="mi">.25s</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.hamburger</span> <span class="nt">span</span> <span class="p">{</span>
    <span class="nl">display</span><span class="p">:</span> <span class="nb">block</span><span class="p">;</span>
    <span class="nl">width</span><span class="p">:</span> <span class="m">20px</span><span class="p">;</span>
    <span class="nl">height</span><span class="p">:</span> <span class="m">1px</span><span class="p">;</span>
    <span class="nl">border-radius</span><span class="p">:</span> <span class="m">3px</span><span class="p">;</span>
    <span class="nl">margin-bottom</span><span class="p">:</span> <span class="m">5px</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.hamburger</span> <span class="nt">span</span> <span class="p">{</span>
    <span class="nl">transition</span><span class="p">:</span> <span class="m">0</span><span class="mi">.5s</span><span class="p">;</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.hamburger</span> <span class="nt">span</span><span class="nd">:nth-last-child</span><span class="o">(</span><span class="nt">1</span><span class="o">)</span> <span class="p">{</span>
    <span class="nl">transform</span><span class="p">:</span> <span class="nf">rotate</span><span class="p">(</span><span class="m">135deg</span><span class="p">)</span> <span class="nf">translate</span><span class="p">(</span><span class="m">-4</span><span class="mi">.5px</span><span class="o">,</span> <span class="m">4</span><span class="mi">.5px</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.hamburger</span> <span class="nt">span</span><span class="nd">:nth-last-child</span><span class="o">(</span><span class="nt">3</span><span class="o">)</span> <span class="p">{</span>
    <span class="nl">opacity</span><span class="p">:</span> <span class="m">0</span><span class="p">;</span>
    <span class="nl">transform</span><span class="p">:</span> <span class="nf">rotate</span><span class="p">(</span><span class="m">135deg</span><span class="p">)</span> <span class="nf">translate</span><span class="p">(</span><span class="m">-10px</span><span class="o">,</span> <span class="m">3px</span><span class="p">);</span>
<span class="p">}</span>

<span class="nc">.menu-toggle.open</span><span class="nd">:checked</span> <span class="o">~</span> <span class="nc">.hamburger</span> <span class="nt">span</span><span class="nd">:nth-last-child</span><span class="o">(</span><span class="nt">2</span><span class="o">)</span> <span class="p">{</span>
    <span class="nl">transform</span><span class="p">:</span> <span class="nf">rotate</span><span class="p">(</span><span class="m">-135deg</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>]]></content><author><name></name></author><summary type="html"><![CDATA[If you are on mobile, or if you shrink the window, you’ll see a hamburger menu with a toggleable sidebar. This is functional with javascript disabled, although some javascript was added to enhance the experience. So, how do you implement it?]]></summary></entry><entry><title type="html">The past decade of blogging</title><link href="https://www.christianbaum.com/blog/2024-11-24-the-past-decade-of-blogging" rel="alternate" type="text/html" title="The past decade of blogging" /><published>2024-11-24T05:32:55-07:00</published><updated>2024-11-24T05:32:55-07:00</updated><id>https://www.christianbaum.com/blog/the-past-decade-of-blogging</id><content type="html" xml:base="https://www.christianbaum.com/blog/2024-11-24-the-past-decade-of-blogging"><![CDATA[<p>Before today, there was only one blog post on my site, from 2020, <a href="/blog/helloable-c">helloable.c</a>. I’m pretty sure nobody has read it. I don’t know, I don’t use analytics, but I never advertised it. My primary motivation for even writing that was to combat imposter syndrome I felt at the time, even though already had 4 years of professional experience at that point. If I could offer a useful blog post, maybe I could be a “real” developer, I thought. Pretty silly reasoning, really! I had a draft for the longest time about using #define in C to implement compile-time templates, which I never finished because the quality didn’t measure up. Honestly, I don’t care to finish it.</p>

<p>Today, I merged my programming and game development related posts from two of my older blogs (and a private journal entry) so that I could start tracking my past. It made me feel kind nostalgic. I’ve been trying to make a successful game for the past decade as a solo developer, and I didn’t, yet. What I did have, was a successful eight years of professional software development, a fun time doing improv comedy, and great personal development. While I am allowing myself to feel nostalgia for the past and wonder what could have been if I sacrificed those things for developing a game, I do not regret it. Instead, I feel excitement for the future.</p>

<p>Juggling personal projects, work, friends, and leisure life is not easy. No matter, I set unrealistic expecations. I expected too much from myself. I started projects with much excitement and gave up on them. I felt guilt and shame for not following through. It affected my social life. If I was playing video games, out socializing, living my life, or even working, I felt guilt that I wasn’t working on my game. Not only was that an unhealthy mindset, the stress I put on myself to accomplish my goals was unproductive in achieving them.</p>

<p>If there is one thing I could say that I regret, it’s not writing more. Nate Silver put out a blog post a few days ago titled <a href="https://www.natesilver.net/p/always-be-blogging">Always. Be. Blogging.</a> which while I don’t care to be a successful blogger, inspired me to reflect today. I read my past blogs and merged them here, starting from over a decade ago. I’m excited that maybe one day, this journey, which has been a dream I’ve had since at least the age of 5 or 6 will be inspiring for someone else. I wish I wrote more about it. Documented or not however, I understand my past of starting projects and not finishing them is hardly unique even if it were better documented. Instead, I’ll just quickly take a look at what I’ve done in the past, and just make a promise: I’ll be blogging a lot more.</p>

<h2 id="a-quick-look-at-the-past-decade-of-my-personal-projects">A quick look at the past decade of my personal projects</h2>

<h3 id="punching-out-cthulhu-project-name">Punching Out Cthulhu (project name)</h3>

<p>Starting in 2011 while I was in high school, This was my first serious attempt at making a video game. It started out Sure I’ve dabbled, but this time I was serious. When it came to coding, I struggled to make any progress. This game became my hyperfixation up until 2014-2015 when I started City Night. My plan started out as me making a silly mobile game about punching monsters based on punch-out. If I stuck to that, I think I could have been successful. Instead, since it became my hyperfixation, it turned into an epic story in my head about love, betrayal, loss , So… scope creep. Maybe someday I’ll pick this back up.</p>

<h3 id="peewees">Peewees</h3>

<p>I thought I would mention this because I found a reference to it when going through christianbaum.com on archive.org. I made a barely functional demo for this in 2013, and I lost the source code. This was originally going to be a lemmings / pikmin style management game. I probably won’t pick this up.</p>

<h3 id="city-night">City Night</h3>

<p>I started this game as a winter game jam game in late 2014. It was supposed to be a cute little NES-style adventure showing how hard it is to survive in a city without a support system. Had I stuck with the original scope of this game, I have no doubt I would be done with this. Like Punching Out Cthulhu, I didn’t, because my perfectionism refused to stick with the original scope. If you start at the beginning and scroll through older posts of this blog, you can see how things quickly got out of control of from what was originally a simple game.</p>

<p>I think I would like to finish the original version of the game in a game jam and also explore ideas I had later on.</p>

<h3 id="kats-dream">Kat’s Dream</h3>

<p>This started out as an infinite runner While my mind loved to try and sabotage it with scope creep, I actually did publish this to Google Play, (source code at <a href="https://github.com/xianbaum/katsdream">Kat’s Dream</a>), but it was quite bad, nobody downloaded it and it was delisted last year for failure to target Google’s newer Android API, so I don’t really count that. I might also pick this one back up some day with the thoughts I had.</p>

<h3 id="stray-kitty">Stray Kitty</h3>

<p>This is probably the most successful thing I’ve done! It has 50k users on the Chrome web store <a href="https://chromewebstore.google.com/detail/stray-kitty/pdiefgmeejbkamgippdjdchpgkdnelbl?hl=en">https://chromewebstore.google.com/detail/stray-kitty/pdiefgmeejbkamgippdjdchpgkdnelbl?hl=en</a> and the source code can be found here. <a href="https://github.com/xianbaum/StrayKitty">https://github.com/xianbaum/StrayKitty</a>. Sometimes I think about expanding on this with more cat behaviors and porting it to other platforms, but I’m not sure, really. Funnily enough, I get offer emails about purchasing it all the time. The most recent offer was $5,000. I’m not going to do that.</p>

<p>I want to write more, but after adding all those posts to my blog and writing this, it’s almost 6am.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Before today, there was only one blog post on my site, from 2020, helloable.c. I’m pretty sure nobody has read it. I don’t know, I don’t use analytics, but I never advertised it. My primary motivation for even writing that was to combat imposter syndrome I felt at the time, even though already had 4 years of professional experience at that point. If I could offer a useful blog post, maybe I could be a “real” developer, I thought. Pretty silly reasoning, really! I had a draft for the longest time about using #define in C to implement compile-time templates, which I never finished because the quality didn’t measure up. Honestly, I don’t care to finish it.]]></summary></entry><entry><title type="html">City Night Journal Entry</title><link href="https://www.christianbaum.com/blog/2022-08-21-city-night-journal-entry" rel="alternate" type="text/html" title="City Night Journal Entry" /><published>2022-08-21T00:00:00-07:00</published><updated>2022-08-21T00:00:00-07:00</updated><id>https://www.christianbaum.com/blog/city-night-journal-entry</id><content type="html" xml:base="https://www.christianbaum.com/blog/2022-08-21-city-night-journal-entry"><![CDATA[<p><em>Note: Below is the only journal entry I have about City Night in a private file. I don’t see why I didn’t make a public blog post about this. Maybe it was too vulnerable for me to say at the time.</em></p>

<p>Last time I visited this document was 4 years ago, and 4 years before that.
But I like the thought of keeping a journal. I’m renaming this document
from timeline to journal. That sounds a little more comforting than a
timeline. And I think I will be a little more proud updating this document.
I feel a little sick opening this document I started. Eight years, this
game has been circling around in my mind.</p>

<p>I have arthritis. It hurts a bit to type this, in addition to the pain of
being reminded by this document,so that’s annoying. I’m getting older. 27.
If I don’t start working on this daily, I won’t have a game at all. This
year I decided it would make more sense to release the game in parts.
But maybe it should be even smaller than that. Episodes, maybe.</p>

<p>This game is very ambitious, so I think to release in episodes is the
wisest choice.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Note: Below is the only journal entry I have about City Night in a private file. I don’t see why I didn’t make a public blog post about this. Maybe it was too vulnerable for me to say at the time.]]></summary></entry><entry><title type="html">Helloable.c</title><link href="https://www.christianbaum.com/blog/2020-12-25-helloable-c" rel="alternate" type="text/html" title="Helloable.c" /><published>2020-12-25T00:00:00-07:00</published><updated>2020-12-25T00:00:00-07:00</updated><id>https://www.christianbaum.com/blog/helloable-c</id><content type="html" xml:base="https://www.christianbaum.com/blog/2020-12-25-helloable-c"><![CDATA[<p>I want to write a little bit about object oriented C, and how to
implement patterns seen in languages like C++ in C, hopefully without
sacrificing performance or elegance. I created <a href="https://gist.github.com/xianbaum/463f13a8d39014131b3f4fa67a241119">helloable.c</a>
as a C interface implementation for comparable C++, in <a href="https://gist.github.com/xianbaum/1407f6a63ed826e4f42e7100c38977e9">helloable.cpp</a>.</p>

<p>C programmers usually code to interfaces in three ways: One, they use #ifdef drop-in
implementations, two, function pointers in structs, or three, a pointer to a vtable.
My implementation uses a vtable, but my implementation also goes an extra step to minimize CPU instructions
to match the C++ equivalent implementation.
that is fully comparable to how interfaces work in languages like Java. One reason
might be that interfaces have overhead. While coding a web app in Java,
you might code to an interface without giving a second thought. But coding for embedded
systems or legacy machines, you might want to consider something else.
Overhead can be avoided entirely if implementations are swapped out using ifdefs at
compile time. I take advantage of this in <a href="https://gitlab.com/xianbaum/cngine">cngine</a>.
However, that doesn’t satisfy every reason to use an interface in object oriented languages.</p>

<p>Requirements of the implementation:</p>
<ul>
  <li>Be at least partially encapsulated, as much as C allows</li>
  <li>Be able to be contained in a collection of other types without sacrificing functionality</li>
  <li>Cast to and from the interface</li>
  <li>Generate comparable assembly to a C++ implementation</li>
</ul>

<p>Three years ago, I made an effort to get close to C++ implementation down to the assembly,
without being ugly and keeping abstractions as much as C allows.</p>

<h2 id="single-inheritance-in-c">Single inheritance in C</h2>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
  <span class="n">Being</span> <span class="n">base</span><span class="p">;</span>
  <span class="kt">char</span> <span class="o">*</span><span class="n">breed</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Animal</span><span class="p">;</span>
</code></pre></div></div>

<p>Single inheritance is very simple in C. The very first member of a struct can be 
cast directly into the first member. One caveat is when accessing the
Animal directly, you need to either cast it to Being, or call the base member.
You can’t call the base members directly from animal, like you can in C++ or
Java. Another drawback is if a struct is declared on the stack or globally,
you can only cast to base class with a pointer.</p>
<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Animal</span><span class="o">*</span> <span class="n">animal</span><span class="p">;</span>
<span class="c1">// ...</span>
<span class="c1">// Pretend animal is a valid, populated Animal.</span>
<span class="c1">// This is valid in C.</span>
<span class="n">Being</span><span class="o">*</span> <span class="n">b</span> <span class="o">=</span> <span class="p">(</span><span class="n">Being</span><span class="o">*</span><span class="p">)</span><span class="n">animal</span><span class="p">;</span>
<span class="c1">// You can access Being-&gt;x with animal-&gt;base-&gt;x, or the casted b-&gt;x</span>
</code></pre></div></div>

<h2 id="interface-inheritance-in-c">Interface inheritance in C</h2>

<p>In order to fully satisfy interfaces, three things are required.</p>

<h3 id="create-the-struct-for-the-interface">Create the struct for the interface</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="n">Helloable</span><span class="p">{</span>
  <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">SayHello</span><span class="p">)(</span><span class="kt">void</span><span class="p">);</span>
  <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">SayGoodbye</span><span class="p">)(</span><span class="k">struct</span> <span class="n">Helloable</span> <span class="k">const</span> <span class="o">**</span><span class="n">helloable</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span>
<span class="p">};</span>
</code></pre></div></div>

<h3 id="put-the-interface-you-want-to-implement-as-a-struct-member">Put the interface you want to implement as a struct member</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">typedef</span> <span class="k">struct</span>
<span class="p">{</span>
  <span class="n">Animal</span> <span class="n">base</span><span class="p">;</span>
  <span class="kt">int</span> <span class="n">barks_per_minute</span><span class="p">;</span>
  <span class="n">Helloable</span> <span class="o">*</span><span class="n">helloable</span><span class="p">;</span>
<span class="p">}</span> <span class="n">Dog</span><span class="p">;</span>
</code></pre></div></div>

<h3 id="after-declaring-the-functions-or-here-implementing-them-create-a-vtable-unique-for-that-struct">After declaring the functions (or here, implementing them) create a vtable unique for that struct</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Dog_PrintStats</span><span class="p">(</span><span class="n">Dog</span> <span class="o">*</span><span class="n">dog</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">Dog_SayHello</span><span class="p">(</span><span class="kt">void</span><span class="p">);</span>
<span class="kt">void</span> <span class="nf">Dog_SayGoodbye</span><span class="p">(</span><span class="n">Helloable</span> <span class="o">**</span><span class="n">helloable</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">);</span>
<span class="n">Helloable</span> <span class="n">DogHelloableVtable</span> <span class="o">=</span> <span class="p">{</span> <span class="n">Dog_SayHello</span><span class="p">,</span> <span class="n">Dog_SayGoodbye</span> <span class="p">};</span>
</code></pre></div></div>

<h3 id="optionally-use-the-constructor-pattern-to-for-creation-functions">Optionally, use the constructor pattern to for creation functions</h3>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Dog</span> <span class="o">*</span><span class="nf">Dog_Create</span><span class="p">()</span>
<span class="p">{</span>
  <span class="n">Dog</span> <span class="o">*</span><span class="n">dog</span> <span class="o">=</span> <span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">Dog</span><span class="p">));</span>
  <span class="n">dog</span><span class="o">-&gt;</span><span class="n">helloable</span> <span class="o">=</span> <span class="o">&amp;</span><span class="p">(</span><span class="n">DogHelloableVtable</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">dog</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="have-a-way-to-access-a-the-struct-implementing-an-interface-struct">Have a way to access a the struct implementing an interface struct</h3>

<p>The interface pointer needs to be passed into the function when called, but 
how can we access members outside of the interface struct?
A naive way to do this is to have a pointer at the top of the interface struct
for the dervi pointer, but that causes several issues. The first issue is struct size.
If every vtable needs to contain a pointer, then every vtable needs to be copied into
the struct instead of having a global vtable, increasing size.</p>

<p>However, using the offsetof keyword defined in stddef.h, we can cast to and from the
base type simply given. This works well because each struct type can have its own unique
implementation, so we know exactly what we are casting to and from. You can use these macros
as a template for casting to and from the interface.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#define ToHelloable(casting) &amp;(casting-&gt;helloable)
#define FromHelloable(type, helloable) \
  ((type*)((char*)helloable - offsetof(type, helloable)))
</span></code></pre></div></div>

<p>We can access Dog and all of its properties, or Being and all of its properties using FromHellable.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">void</span> <span class="nf">Dog_SayGoodbye</span><span class="p">(</span><span class="n">Helloable</span> <span class="o">**</span><span class="n">helloable</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">name</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">Being</span> <span class="o">*</span><span class="n">self</span> <span class="o">=</span> <span class="p">(</span><span class="n">Being</span><span class="o">*</span><span class="p">)</span><span class="n">FromHelloable</span><span class="p">(</span><span class="n">Dog</span><span class="p">,</span> <span class="n">helloable</span><span class="p">);</span>
  <span class="n">printf</span><span class="p">(</span><span class="s">"Woof-woof, from %s to %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">self</span><span class="o">-&gt;</span><span class="n">name</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>

<p>While you can just get the helloable by accessing member <code class="language-plaintext highlighter-rouge">thing-&gt;helloable</code>,
I wrote a ToHelloable macro to complement the FromHelloablemacro. Here, it’s used
to cast <code class="language-plaintext highlighter-rouge">dog</code>, <code class="language-plaintext highlighter-rouge">cat</code> and <code class="language-plaintext highlighter-rouge">person</code> to helloable.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="n">my_helloable_array</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">ToHelloable</span><span class="p">(</span><span class="n">dog</span><span class="p">);</span>
  <span class="n">my_helloable_array</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">ToHelloable</span><span class="p">(</span><span class="n">cat</span><span class="p">);</span>
  <span class="n">my_helloable_array</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="n">ToHelloable</span><span class="p">(</span><span class="n">person</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="collections">Collections</h2>

<p>I demostrated it working by having a collection of helloables. When calling
<code class="language-plaintext highlighter-rouge">SayHello</code> and <code class="language-plaintext highlighter-rouge">SayGoodbye</code>, the caller knows nothing about the implementation,
but the functions are unique and successfully access members of <code class="language-plaintext highlighter-rouge">Dog</code>, <code class="language-plaintext highlighter-rouge">Cat</code>, and <code class="language-plaintext highlighter-rouge">Person</code>.</p>

<div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">3</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="n">Helloable</span> <span class="o">**</span><span class="n">helloable</span> <span class="o">=</span> <span class="n">my_helloable_array</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
    <span class="p">(</span><span class="o">*</span><span class="n">helloable</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SayHello</span><span class="p">();</span>
    <span class="p">(</span><span class="o">*</span><span class="n">helloable</span><span class="p">)</span><span class="o">-&gt;</span><span class="n">SayGoodbye</span><span class="p">(</span><span class="n">helloable</span><span class="p">,</span> <span class="s">"Jack"</span><span class="p">);</span>
  <span class="p">}</span>
</code></pre></div></div>

<h2 id="drawbacks-and-things-to-consider">Drawbacks and things to consider</h2>

<h3 id="performance">Performance</h3>

<p>On modern machines, having everything coded to an interface is cheap.
But on legacy machines and embedded hardware, it’s not so much. Having 
to dereference so many function pointers is not exactly ideal when you
need to squeeze every last bit of performance.</p>

<h3 id="syntax-and-macros">Syntax and macros</h3>

<p>If a base struct implements an interface and a derived struct doesn’t, due to
how the offsetof macro works, you need to cast the struct to the base interface
or pass the base member. If both a base struct and a derived struct implement an
interface differently, you should not cast to the base struct as it will use
the base struct implementation instead of the derived struct implementation.</p>

<h3 id="refactoring-and-abstraction">Refactoring and abstraction</h3>

<p>While it might be nice to know explicitly which function is virtual or not due to
the syntax of calling a function pointer versus a normal function, the abstraction
between the two are gone. If you decide to make the void function <code class="language-plaintext highlighter-rouge">Cat_PrintStats</code> an interface,
then you’ll probably need to change every call to <code class="language-plaintext highlighter-rouge">Cat_PrintStats</code> to accommodate
this change. Also, by having pointers to vtables containing pointers to functions,
if called explicitly, it is painfully obvious which function is called via interface
and which function is not. The same issues arise if you want to go from an interface
to a normal function.</p>

<h3 id="memory-management">Memory management</h3>

<p>Depending on your memory management patterns, inheritance could cause some confusion
if you lose your reference to the base class. If you free a pointer to an interface,
you will likely crash your program or cause memory corruption. Memory management can
be made easier using this using the destructor pattern by putting a destructor in an
interface or base struct.</p>

<h2 id="more">More</h2>

<p>I wrote some more notes in the actual gists for the struct. Check out <a href="https://gist.github.com/xianbaum/463f13a8d39014131b3f4fa67a241119">Complete gist for helloable.c</a> and <a href="https://gist.github.com/xianbaum/1407f6a63ed826e4f42e7100c38977e9">the C++ equivalent gist, helloable.cpp</a>.</p>

<p>I wrote a lot about the implementation years after I actually implemented it.
I might re-visit the implementation more with fresh eyes and change it a little bit.
I don’t want to mislead people, so if I made a mistake writing, please contact me.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I want to write a little bit about object oriented C, and how to implement patterns seen in languages like C++ in C, hopefully without sacrificing performance or elegance. I created helloable.c as a C interface implementation for comparable C++, in helloable.cpp.]]></summary></entry><entry><title type="html">Lua implementation: Day 3</title><link href="https://www.christianbaum.com/citynight/2018/05/17/lua-implementation-day-3.html" rel="alternate" type="text/html" title="Lua implementation: Day 3" /><published>2018-05-17T02:40:00-07:00</published><updated>2018-05-17T02:40:00-07:00</updated><id>https://www.christianbaum.com/citynight/2018/05/17/lua-implementation-day-3</id><content type="html" xml:base="https://www.christianbaum.com/citynight/2018/05/17/lua-implementation-day-3.html"><![CDATA[<!-- blank line -->
<figure class="video_container">
  <video controls="true" allowfullscreen="true">
    <source src="/videos/2018-05-17 02-08-52.webm" type="video/webm" />
  </video>
</figure>
<!-- blank line -->

<p>The lua console is essentially complete. At this point, it should be very easy to add anything I may need to it. I don’t need anything specific right away, so I plan on adding features as I need them and be done with the console.  There is a tiny bug with the console buffer printing old strings that I may or may not fix - it’s visible in the video above. I get a warm feeling just playing with it, seeing characters pop-up and be removed dynamically. Is that weird? :)</p>

<p>Are you programming a game in a C compatible language and interested in integrating Lua in your game? Do it! <a href="https://www.lua.org/manual/">The documentation is in-depth</a> and there is a great community at <a href="https://lua-users.org">lua-users.org</a> It is easy to use. For me, the most helpful sections of the documentation was that of <a href="https://www.lua.org/pil/28.1.html">usertypes</a>, and peaking at an <a href="http://lua-users.org/wiki/UserDataExample">example of usertypes in action</a>.</p>]]></content><author><name></name></author><category term="citynight" /><summary type="html"><![CDATA[]]></summary></entry><entry><title type="html">Lua implementation: Day 2</title><link href="https://www.christianbaum.com/citynight/2018/05/16/lua-implementation-day-2.html" rel="alternate" type="text/html" title="Lua implementation: Day 2" /><published>2018-05-16T03:00:00-07:00</published><updated>2018-05-16T03:00:00-07:00</updated><id>https://www.christianbaum.com/citynight/2018/05/16/lua-implementation-day-2</id><content type="html" xml:base="https://www.christianbaum.com/citynight/2018/05/16/lua-implementation-day-2.html"><![CDATA[<p>I feel rather productive today! I’ve done quite a bit since the last post and now we are able to execute game commands on the fly with the Lua console, such as jumping to any map on the fly.</p>

<!-- blank line -->
<figure class="video_container">
  <video controls="true" allowfullscreen="true">
    <source src="/videos/2018-05-16 02-38-19.webm" type="video/webm" />
  </video>
</figure>
<!-- blank line -->

<p>Bonus: Map 0 is the first thing I ever  created for this game in December of 2014! I started drawing this map even before doing any programming. Sadly, the game has changes quite a bit and it uh, clashes with the new art style I’ve chosen. In fact, below is my first screenshot of the game. I was using Love2D at the time, which incidentally uses Lua. Since then, I’ve changed the game quite a bit and City Night is programmed in C now.</p>

<p><img src="/images/2018-05-16-citynight-first-screenshot.png" alt="First screenshot of City Night" /></p>

<p>Hopefully, I can finish up what I want to do with Lua tomorrow and we can move on.</p>]]></content><author><name></name></author><category term="citynight" /><summary type="html"><![CDATA[I feel rather productive today! I’ve done quite a bit since the last post and now we are able to execute game commands on the fly with the Lua console, such as jumping to any map on the fly.]]></summary></entry><entry><title type="html">The first half of 2018</title><link href="https://www.christianbaum.com/citynight/2018/05/15/the-first-half-of-2018.html" rel="alternate" type="text/html" title="The first half of 2018" /><published>2018-05-15T04:00:00-07:00</published><updated>2018-05-15T04:00:00-07:00</updated><id>https://www.christianbaum.com/citynight/2018/05/15/the-first-half-of-2018</id><content type="html" xml:base="https://www.christianbaum.com/citynight/2018/05/15/the-first-half-of-2018.html"><![CDATA[<p>Holy CRAP!!!</p>

<p>What happened to the time? It’s been nearly 6 months, and I haven’t done much. And to prevent another repeat of 2017, I’d better get to it. Short update today because it is 4 AM and I am TIRED.</p>

<p>So, what have I done in the past freakin’ year? Well, so for the first 5 months, I’ve been working a bit on the music. That’s probably the most consistent thing I’ve been doing. Code wise, I refactored a lot, mostly in the past week. Today, I started progress on an interactive Lua console like shown below.</p>

<!-- blank line -->
<figure class="video_container">
  <video controls="true" allowfullscreen="true">
    <source src="/videos/2018-05-15 03-13-02.webm" type="video/webm" />
  </video>
</figure>
<!-- blank line -->

<p>That’s all for today! Again, it’s not much, but I hope to have more frequent updates.</p>]]></content><author><name></name></author><category term="citynight" /><summary type="html"><![CDATA[Holy CRAP!!!]]></summary></entry><entry><title type="html">The year of two thousand and seventeen</title><link href="https://www.christianbaum.com/citynight/2018/01/12/the-year-of-two-thousand-and-seventeen.html" rel="alternate" type="text/html" title="The year of two thousand and seventeen" /><published>2018-01-12T04:18:20-07:00</published><updated>2018-01-12T04:18:20-07:00</updated><id>https://www.christianbaum.com/citynight/2018/01/12/the-year-of-two-thousand-and-seventeen</id><content type="html" xml:base="https://www.christianbaum.com/citynight/2018/01/12/the-year-of-two-thousand-and-seventeen.html"><![CDATA[<p>Is it too late in January to reflect upon 2017?</p>

<p>So, this is my first post on this blog, called “progress” for City Night, a game I am working on. The thing is, I didn’t make nearly as much progress as I had hoped for in 2017. Actually, I haven’t made as much progress as I had hoped for 2018, either. It’s fine, but it makes me a little bit sad. I started this blog as a means of helping me document what I do for City Night. I called it “progress” because I want this blog to help me make progress on City Night. Previously, I had a tumblr blog at punchingoutcthulhu.tumblr.com which contains old posts for very old versions of City Night. I actually made a tumblr command line poster so that I would not have to go on the site to post, but it turns out, Jekyll is so much more convenient for writing posts like these. I may still write post on there just for the gamedev community on Tumblr, but I o they would be pretty condensed and for more in-depth updates, this would be the site to go to.</p>

<p><em>(Note: Posts from the progress blog and tumblr blog mentioned above have been merged here.)</em></p>

<h2 id="city-night">City Night</h2>

<p>If you are interested in seeing what it is like so far, there is a demo from early last year I frantically threw together. <a href="https://xianbaum.itch.io/city-night">It can be acquired here, on itch.io</a>. There is also an older version on there. These demos are in no way complete (in fact I would hardly consider them playable) and I only made them because a group had a “demo day” and I tried to meet the deadline of it. I hope to put together more demos in the future!</p>

<p><img src="/images/2018-01-12-citynight-screenshot.png" alt="Screenshot of City Night" /></p>

<p>I started work on the first “dungeon” (that’s what I call them) in City Night: the school. The location is mapped out completely, but not all of the tilesets exist yet. Most of them just use this basic red white and black tileset, but the layouts are essentially done.</p>

<p><img src="/images/2018-01-12-citynight-screenshot2.png" alt="Screenshot of City Night showing the red white and black tileset" /></p>

<p>I also began work on an essential part of City Night: items and enemies. The idea was to have people chase you, and in Home Alone fashion, you can only defend yourself with your resourcefulness and traps, but that is not implemented. In DD13 demo linked above, there’s something really silly you can do that was me starting on this idea. In the menu, you can use the light on the paper that you have and you can light it on fire. It does absolutely nothing except that a fireball follows you on your side. It looks absolutely silly and I love it.</p>

<p>On the technical side, I made many things for City Night:</p>

<ol>
  <li>Logger</li>
  <li>Asset resolver</li>
  <li>Memory leak detector</li>
  <li>A method for using interfaces in C</li>
  <li>Type-safe generics in C using macros to define them</li>
</ol>

<p>I need to rewrite quite a bit of the code, specifically for characters and items, since the way it is currently programmed is less than ideal and a bit of a mess (but at the time, I thought my methods were the was the greatest). Basically, before, I had subroutines for each actor (an actor is what I call any interactable thing). You could add or remove a struct containing a function pointer and data. I called them subroutines but that’s not exactly the right term. That was how I was going to differentiate every actor in the game. I ran into problems with this, specifically if I wanted to access data from a certain subroutine that may or may not have existed, and ran into problems with the order that they executed. Just to clarify, I am still going to do this for smaller things, like generic status effects! Just not for every actor, and I am not using it to differentiate one actor for another. That’s why I looked into class-based and interface-based in C.</p>

<p>Fun-fact: While taking screenshots tonight, I encountered a game crash caused by a missing idle animation that was frustrating me I coudln’t find out the root cause.</p>

<h2 id="city-night-tools">City Night Tools</h2>

<p>Late December of 2016, I made a crude, buggy, animation tool that assisted me in making animations. I made it in JavaScript. I started on a Javascript map editor, too, as I had been using Tiled before, but it was also very crude and buggy. I could have built on top of that, but the code was so ugly and unmaintainable. To help me learn Angular and TypeScript, I started writing my own tools for City Night - and I largely rewrote the sprite editor and map editor.</p>

<p><img src="/images/2018-01-12-mapeditor.jpg" alt="Pictured is a screenshot of my map editor" /></p>

<p>It’s not complete yet, unfortunately. The map editor is close to being done, but I also want to port my animation editor and write a generic sequence scripter (thing dialog boxes, cutscene and flags). It’s a little discouraging that I was unable to finish my tooling in a year. I haven’t been consistently working on it, though. I don’t think it is that the tools should take over a year to make. My goal is to finish them by the end of January. I am not sure if it is attainable, as I have two and a half weeks, but it is a challenge to aim for.</p>

<h2 id="arthritis">Arthritis</h2>

<p>Well last year, I developed an undifferentiated arthritis and that among other things made me feel kind of bummed. I fell into a rut and I would either have days where I thought “Well, I need to complete City Night before I die” and other days where I thought “It’s hopeless”. Arthritis is not that serious but chronic pain can discouraging be sometimes. I thought my life was over.</p>

<p>I started taking classes at an improv theater because I needed to meet friends and I needed to do something that would inspire me to have hope in life. I made a lot of friends and I think it was a lot of fun. All and all, my mental state has generally much improved from last year.</p>

<h2 id="heres-to-progress">Here’s to progress!</h2>]]></content><author><name></name></author><category term="citynight" /><summary type="html"><![CDATA[Is it too late in January to reflect upon 2017?]]></summary></entry></feed>