<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://zanderlowry.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://zanderlowry.com/" rel="alternate" type="text/html" hreflang="en" /><updated>2026-09-01T06:56:45+00:00</updated><id>https://zanderlowry.com/feed.xml</id><title type="html">Alexander Lowry</title><subtitle>Software engineer. Notes on code, models and miniatures, and things worth memorizing.</subtitle><author><name>Alexander Lowry</name></author><entry><title type="html">WASM for Offline-First Collaboration</title><link href="https://zanderlowry.com/posts/wasm-offline-collaboration/" rel="alternate" type="text/html" title="WASM for Offline-First Collaboration" /><published>2026-09-01T00:00:00+00:00</published><updated>2026-09-01T00:00:00+00:00</updated><id>https://zanderlowry.com/posts/wasm-offline-collaboration</id><content type="html" xml:base="https://zanderlowry.com/posts/wasm-offline-collaboration/"><![CDATA[<p>My customers on <a href="https://thankyoufive.live">Thank You, Five!</a> kept losing WiFi in the middle of rehearsals, and the software has realtime collaboration. Keeping both offline capability and realtime collaboration is a contradiction.</p>

<p>Realtime collaboration requires a constant connection. Spotty WiFi means queuing actions up and sending them later. I am building stage management software for theatre teams, and theatres, with old buildings, thick walls, half of them working out of a basement, are close to the worst case for this. Attenuation is bad through cinderblocks.</p>

<p>WASM fit the problem perfectly. You can compile the same code for your server’s architecture and the VM that runs in the browser, and it works identically. I wrote the reconciliation algorithm in Rust and compiled it for the client, so every client runs an exact copy of the server’s algorithm. Actions get a temporary timestamp and edits apply locally. When a client that dropped off comes back, the server rewinds time and runs reconciliation against all client actions. The divergent clocks stop mattering, so long as two people aren’t editing the exact same characters. The server reconciles, sends the truth back to every client, and each one re-applies the same history plus whatever it has done since. Server and client settle on the full truth through a short conversation, and the document comes out perfectly intact.</p>

<p>To my own surprise, it rescued a document of mine before it ever rescued a customer’s. I was dogfooding. I’d volunteered to take minutes at a theatre board meeting, when a double-escaping bug started dropping escaped escape sequences into the text I was typing. My undo made it worse, because undo applies deltas in reverse by character index and the indices were corrupt. But the history had every delta from the beginning, so I reconstructed the whole document by replaying them in order. The design I built for bad WiFi turned out to be the thing that made a bad bug recoverable. The bug has since been fixed, but I’m glad I went the way I did.</p>

<p>It’s fast, too. WASM runs slower than native, but considerably faster than JavaScript. It has picked up real speedups over the last few Chrome releases, and new proposals for streaming the bytecode and better dynamic linking are quickly eliminating its downsides. The era of WASM is genuinely cool.</p>]]></content><author><name>Alexander Lowry</name></author><summary type="html"><![CDATA[Theatres have thick walls and bad WiFi. Compiling the reconciliation algorithm to WebAssembly let every client run an exact copy of the server's logic, so documents survive dropped connections — and one very bad bug.]]></summary></entry><entry><title type="html">The Idea</title><link href="https://zanderlowry.com/posts/drinkrig-the-idea/" rel="alternate" type="text/html" title="The Idea" /><published>2024-10-17T00:00:00+00:00</published><updated>2024-10-17T00:00:00+00:00</updated><id>https://zanderlowry.com/posts/drinkrig-the-idea</id><content type="html" xml:base="https://zanderlowry.com/posts/drinkrig-the-idea/"><![CDATA[<p>
  Before I could do much, I had to learn how to do anything at all. I had no
  experience in model making or mini painting before, so I started with some
  industrial pieces. Of course, I went straight to
  <a href="https://thingiverse.com">Thingiverse</a> to look. A
  <a href="https://www.thingiverse.com/thing:4924617">crate</a> by
  <code>Printed-Toys</code> and an
  <a href="https://www.thingiverse.com/thing:2441340">electrical box</a> by
  <code>NYC3D</code> work very well for this purpose. I also thought a drinkrig
  could use a crane, so I found
  <a href="https://www.thingiverse.com/thing:4755523">this one</a> by
  <code>Mikesrailway</code>. It's an old rail crane, which I think the
  inhabitants of a drinkrig might cannibalize for moving things around.
</p>

<figure>
  <img src="/assets/img/drinkrig/the-idea/first-crates.jpeg"
       alt="Two printed crates side by side; the upper one bare white plastic with a wash, the lower one primed first and noticeably smoother.">
  <figcaption>
    The top is white PLA with only a weathering wash. The bottom is a primer then
    a weathering wash. The primer helps hide the layer lines from printing.
  </figcaption>
</figure>

<figure>
  <img src="/assets/img/drinkrig/the-idea/painting-process.jpeg"
       alt="Several test pieces painted in different bright colors over a gray base, all reading as muddy.">
  <figcaption>
    Trying different colors. Bright colors on the gray base doesn't work well. It
    ends up very muddy.
  </figcaption>
</figure>

<figure>
  <img src="/assets/img/drinkrig/the-idea/final-weathered.jpeg"
       alt="A finished crate with convincing weathered, rusted paint.">
  <figcaption>
    Final look process gives what I think is a good look: First, print in white.
    You can go darker but you can't go lighter. Then two layers of a thicker
    primer, a layer of color, then a wash for weathering.
  </figcaption>
</figure>

<figure>
  <img src="/assets/img/drinkrig/the-idea/photo-test-a.jpeg"
       alt="The test pieces photographed under flat diffuse LED panels standing in for daylight.">
  <figcaption>
    Testing daytime light. All I have is diffuse LED panels, so this obviously
    isn't very convincing. Perhaps I just need to take these outside. Color never
    works the way you expect when you first shine those lights on it.
  </figcaption>
</figure>

<figure>
  <img src="/assets/img/drinkrig/the-idea/photo-test-b.jpeg"
       alt="The same test pieces lit blue to simulate night.">
  <figcaption>
    Testing night lighting. Not sure if I love this, but blue light might work
    better than darkness for night.
  </figcaption>
</figure>

<p>
  And with that, I had my proof of concept. Of course, after your first success,
  your confidence shoots up tremendously, so I went on to work on
  <a href="/posts/drinkrig-girders/">the main truss</a>.
</p>]]></content><author><name>Alexander Lowry</name></author><summary type="html"><![CDATA[Proof of concept for the drinkrig: printing industrial pieces from Thingiverse and working out a paint process that reads as rusted metal.]]></summary></entry><entry><title type="html">The Drinkrig</title><link href="https://zanderlowry.com/posts/drinkrig/" rel="alternate" type="text/html" title="The Drinkrig" /><published>2024-10-17T00:00:00+00:00</published><updated>2024-10-17T00:00:00+00:00</updated><id>https://zanderlowry.com/posts/drinkrig</id><content type="html" xml:base="https://zanderlowry.com/posts/drinkrig/"><![CDATA[<figure class="hero">
  <img src="/assets/img/drinkrig/overview/full-day.jpeg"
       alt="The finished drinkrig model: a tall lattice tower carrying stacked platforms, sheds and a greenhouse, standing in daylight above a bed of clouds.">
  <figcaption>The completed drinkrig.</figcaption>
</figure>

<p>
  Recently, one of my friends started an
  <a href="http://apocalypse-world.com/">Apocalypse World</a> game where he
  homebrewed the setting. Gideon is an imaginative and vivid storyteller, so I
  was instantly enthralled by his verbal pictures of this world he had imagined:
</p>

<figure class="quote">
  <blockquote>
    <p>
      My friends, the world you know is drowned. Generations ago, the machines of
      the old world smothered the land in dense, sulfurous, acutely toxic clouds.
      These rusty yellow clouds came to be colloquially known as the sulfur sea.
      Humanity was forced to seek safety above the sea. Generations later,
      descendants of the wealthy survivors of the smothering assumed all walks of
      life, and the name of the Earth was lost. The Earth is dead, gentlemen.
      Long live the <em>Ochrelands</em>.
    </p>
  </blockquote>

  <blockquote>
    <p>
      Some inhabitants of today's brutal Ochrelands found solace above the sea on
      stilted <strong>drinkrigs</strong>, like the old world's oil rigs, that
      stand high above the clouds and support large, unmoving populations. Many
      of them also pump water up from below the sulfur sea, hence their name and
      their relative security.
    </p>
  </blockquote>

  <figcaption>
    Gideon, on the setting of his <cite>Apocalypse World</cite> game.
  </figcaption>
</figure>

<p>
  In just two paragraphs, so much sprang to mind for me. I had bought 3D printers
  to make game miniatures, and I hadn't yet. So I got to work.
</p>

<section aria-labelledby="process-posts">
  <h2 id="process-posts">Process Posts</h2>
  <ol>
    <li><a href="/posts/drinkrig-the-idea/">The Idea</a></li>
    <li><a href="/posts/drinkrig-girders/">3D Printing Girders</a></li>
  </ol>
</section>

<section aria-labelledby="photos">
  <h2 id="photos">Photos</h2>

  <figure>
    <img src="/assets/img/drinkrig/overview/full-night.jpeg"
         alt="The whole drinkrig at night, its windows and lamps glowing warm against dark clouds.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/lower-night.jpeg"
         alt="The lower deck of the drinkrig at night, lit from within.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/coke-machine.jpeg"
         alt="A tiny H0-scale Coca-Cola vending machine tucked into a back corner of the rig, spotlit by a gooseneck lamp.">
    <figcaption>
      When I found this H0-scale coke machine, I knew exactly what I had to do
      with it. It's a detail tucked away in a back layer, but it still gets the
      hero treatment with the gooseneck lamp.
    </figcaption>
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/shed-night.jpeg"
         alt="A small shed on the rig at night, with a miniature notice sign posted beside the door.">
    <figcaption>
      The tiny notice sign here is really funny to me for some reason.
    </figcaption>
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/upper-night.jpeg"
         alt="The upper platforms of the drinkrig at night.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/upper-day.jpeg"
         alt="The upper platforms of the drinkrig in daylight.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/shed-day.jpeg"
         alt="The shed on the rig in daylight, showing weathered paint and rust.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/greenhouse-a.jpeg"
         alt="Inside the drinkrig's greenhouse: rows of tiny plants over a textured dirt floor.">
  </figure>

  <figure>
    <img src="/assets/img/drinkrig/overview/greenhouse-b.jpeg"
         alt="A second view into the greenhouse, showing the dirt texture and planting beds.">
    <figcaption>
      I love the dirt on the floor in here. The plants are one touch that made
      the greenhouse become clearer, and gave it complexity and color, but the
      texture of the dirt really sells it.
    </figcaption>
  </figure>
</section>]]></content><author><name>Alexander Lowry</name></author><summary type="html"><![CDATA[Building a tabletop miniature of a drinkrig — a stilted settlement standing above the toxic clouds of the Ochrelands.]]></summary></entry><entry><title type="html">3D Printing Girders</title><link href="https://zanderlowry.com/posts/drinkrig-girders/" rel="alternate" type="text/html" title="3D Printing Girders" /><published>2024-10-16T00:00:00+00:00</published><updated>2024-10-16T00:00:00+00:00</updated><id>https://zanderlowry.com/posts/drinkrig-girders</id><content type="html" xml:base="https://zanderlowry.com/posts/drinkrig-girders/"><![CDATA[<p>
  After
  <a href="/posts/drinkrig-the-idea/">learning the basics</a>
  from my first 3D-printed components, I got to work on the drinkrig itself. The
  core part of this project was obviously going to be the central structure that
  supported a drink rig. I had never drafted anything before, and I knew I wasn't
  going to be able to create something with any complexity quickly. So I set out
  to <a href="https://thingiverse.com">Thingiverse</a> to see if I could find
  what I was looking for.
</p>

<p>
  I found <a href="https://www.thingiverse.com/thing:2424769">this model</a> by
  user <code>torleif</code>, which is an OpenSCAD file that allowed me to make
  the truss to my exact size.
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/truss.png"
       alt="CAD drawing of a square lattice truss tower.">
</figure>

<p>
  I then cut it in quarters diagonally, and presto, it was easy to print!
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/flat.jpeg"
       alt="Four flat truss sides printed as separate pieces, lying on the print bed.">
  <figcaption>
    As you can see, the plate side looks much nicer than the top side. Instead of
    spending time ironing, I can just put the worse side on the inside.
  </figcaption>
</figure>

<p>
  Then I can paint the pieces and glue them together.
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/painted.jpeg"
       alt="The assembled truss painted gray with brown rust streaks running down it.">
  <figcaption>
    A base gray plus a brownish wash on the top sides makes a wonderful rust. If
    you look closely, you can see the weird texture on the inside. But it's more
    of a background than anything.
  </figcaption>
</figure>

<p>
  Fantastic! Next, for a sense of scale, I thought I'd add a ladder up the side.
  This wasn't very hard to draft, even with my low skills. I'm working at H0
  scale, which is 1:87. That makes the ladder very small indeed!
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/ladder.jpeg"
       alt="A printed ladder only a few millimeters wide, thinner than a finger.">
</figure>

<p>
  I then found a <a href="https://www.thingiverse.com/thing:6115872">fire escape</a>,
  and, after some really fiddly gluing and painting, started to arrange the fire
  escape on the truss.
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/fire-escape.jpeg"
       alt="The tiny ladder and fire escape crudely arranged against the girder, with mold-a-rama figures visible behind.">
  <figcaption>
    You might recognize a few mold-a-rama objects in the back. 3D printing from
    an earlier age.
  </figcaption>
</figure>

<p>
  The final product looks really nice!
</p>

<figure>
  <img src="/assets/img/drinkrig/girders/done.jpeg"
       alt="The finished truss with fire escape and ladder attached, rising out of a sea of fluffy clouds.">
</figure>

<p>
  And with the truss done, it's time to move on to the upper (more complex) parts
  of this build.
</p>]]></content><author><name>Alexander Lowry</name></author><summary type="html"><![CDATA[Drafting a parametric truss in OpenSCAD, printing it in quarters, and adding a 1:87 ladder and fire escape.]]></summary></entry></feed>