<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Jeremy's blog]]></title><description><![CDATA[Writings of Jeremy Rose, sometimes technical.]]></description><link>https://blog.nornagon.net/</link><image><url>https://blog.nornagon.net/favicon.png</url><title>Jeremy&apos;s blog</title><link>https://blog.nornagon.net/</link></image><generator>Ghost 4.48</generator><lastBuildDate>Wed, 01 Apr 2026 02:57:42 GMT</lastBuildDate><atom:link href="https://blog.nornagon.net/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Sign your git commits!]]></title><description><![CDATA[<p>Hey did you know that anyone can upload a commit to GitHub with your name and email? Look, I&apos;m Linus Torvalds:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-11.08.20-AM.png" class="kg-image" alt loading="lazy" width="384" height="158"><figcaption>definitely Linus Torvalds, look it&apos;s got his picture and everything</figcaption></figure><p>When you make a git commit, git pulls your name and email from your git</p>]]></description><link>https://blog.nornagon.net/sign-your-git-commits/</link><guid isPermaLink="false">634d992adf7b250001665d7f</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Mon, 17 Oct 2022 23:10:53 GMT</pubDate><content:encoded><![CDATA[<p>Hey did you know that anyone can upload a commit to GitHub with your name and email? Look, I&apos;m Linus Torvalds:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-11.08.20-AM.png" class="kg-image" alt loading="lazy" width="384" height="158"><figcaption>definitely Linus Torvalds, look it&apos;s got his picture and everything</figcaption></figure><p>When you make a git commit, git pulls your name and email from your git configuration, and writes it into the git database. GitHub uses that data to look up a GitHub user based on the email, and shows the commit as coming from that author. But wait, what&apos;s this?</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-11.10.00-AM.png" class="kg-image" alt loading="lazy" width="98" height="41"></figure><p>The commit is showing up as &quot;Unverified&quot;! Okay, phew, maybe GitHub doesn&apos;t have a huge security hole.</p><p>Except it kind of does! Because unless you&apos;ve turned this on in your <a href="https://github.com/settings/keys">settings</a>:</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-3.21.20-PM.png" class="kg-image" alt loading="lazy" width="617" height="133" srcset="https://blog.nornagon.net/content/images/size/w600/2022/10/Screen-Shot-2022-10-17-at-3.21.20-PM.png 600w, https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-3.21.20-PM.png 617w"></figure><p>anyone can create commits on GitHub that look like they were written by you!</p><hr><h2 id="but-ugh-who-wants-to-deal-with-gpg">But ugh, who wants to deal with GPG</h2><p>Nobody.</p><p>But you don&apos;t have to! Since Git 2.34.0 (released Nov 2021), you can sign commits using the same SSH key you use to push commits to GitHub. And it&apos;s super easy to set up. Here, I&apos;ll walk you through it.</p><p>First, make sure your version of Git is newer than 2.34.0:</p><pre><code class="language-shell">$ git --version
git version 2.38.0</code></pre><p>Then, tell Git you want to sign your commits with your SSH key:</p><pre><code class="language-shell">$ git config --global gpg.format ssh
$ git config --global commit.gpgSign true
$ git config --global tag.gpgSign true</code></pre><p>If you have more than one SSH key on your machine, you should also tell Git which one to use (by default it will use the first one listed in <code>ssh-add -L</code>):</p><pre><code class="language-shell">$ git config --global user.signingKey ~/.ssh/github_key.pub</code></pre><p>And lastly, let GitHub know which key(s) you are going to be using to sign your commits. Go to your <a href="https://github.com/settings/keys">key settings</a>, click &quot;New SSH Key&quot;, and be sure to select &quot;Signing Key&quot; as the key type.</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-3.34.52-PM.png" class="kg-image" alt loading="lazy" width="823" height="313" srcset="https://blog.nornagon.net/content/images/size/w600/2022/10/Screen-Shot-2022-10-17-at-3.34.52-PM.png 600w, https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-3.34.52-PM.png 823w" sizes="(min-width: 720px) 720px"></figure><p>And that&apos;s all! Now all your commits will show up with the little &quot;Verified&quot; badge on GitHub.</p><hr><p>One more step you might want to take is to <a href="https://github.com/settings/keys">turn on Vigilant Mode</a>. That will make GitHub&apos;s UI show commits that have your email, but <em>haven&apos;t</em> been signed by one of your keys, as &quot;Unverified&quot;. That serves as an extra warning to anyone who might come across a pretender trying to pass their code off as yours that something is afoot. It does have the downside that all the commits you made before you started signing your commits will also show as &quot;Unverified&quot;. Such is the price of progress!</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-4.01.48-PM.png" class="kg-image" alt loading="lazy" width="726" height="407" srcset="https://blog.nornagon.net/content/images/size/w600/2022/10/Screen-Shot-2022-10-17-at-4.01.48-PM.png 600w, https://blog.nornagon.net/content/images/2022/10/Screen-Shot-2022-10-17-at-4.01.48-PM.png 726w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[UI Layout Algorithms]]></title><description><![CDATA[<p>Roguelikes tend to have a lot of UI. And, frequently, it&apos;s <em>fiddly</em> UI&#x2014;there are lots of things to display, with deep and complex information. So UI layout is a pretty important part of building a roguelike.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png" class="kg-image" alt loading="lazy" width="1756" height="822" srcset="https://blog.nornagon.net/content/images/size/w600/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 600w, https://blog.nornagon.net/content/images/size/w1000/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1600w, https://blog.nornagon.net/content/images/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1756w" sizes="(min-width: 720px) 720px"><figcaption>Nethack&apos;s inventory and status line UI</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/image-1.png" class="kg-image" alt loading="lazy" width="478" height="513"><figcaption>Cogmind&apos;</figcaption></figure>]]></description><link>https://blog.nornagon.net/ui-layout-algorithms/</link><guid isPermaLink="false">6099a3d57b9110000130184d</guid><category><![CDATA[Adrift]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Tue, 11 May 2021 04:00:01 GMT</pubDate><content:encoded><![CDATA[<p>Roguelikes tend to have a lot of UI. And, frequently, it&apos;s <em>fiddly</em> UI&#x2014;there are lots of things to display, with deep and complex information. So UI layout is a pretty important part of building a roguelike.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png" class="kg-image" alt loading="lazy" width="1756" height="822" srcset="https://blog.nornagon.net/content/images/size/w600/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 600w, https://blog.nornagon.net/content/images/size/w1000/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1600w, https://blog.nornagon.net/content/images/2021/05/Screen-Shot-2021-05-10-at-8.50.02-PM.png 1756w" sizes="(min-width: 720px) 720px"><figcaption>Nethack&apos;s inventory and status line UI</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/image-1.png" class="kg-image" alt loading="lazy" width="478" height="513"><figcaption>Cogmind&apos;s part list UI</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/image-2.png" class="kg-image" alt loading="lazy" width="1640" height="992" srcset="https://blog.nornagon.net/content/images/size/w600/2021/05/image-2.png 600w, https://blog.nornagon.net/content/images/size/w1000/2021/05/image-2.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2021/05/image-2.png 1600w, https://blog.nornagon.net/content/images/2021/05/image-2.png 1640w" sizes="(min-width: 720px) 720px"><figcaption>The advanced inventory UI in Cataclysm: Dark Days Ahead</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/test.png" class="kg-image" alt loading="lazy" width="320" height="214"><figcaption>Part of Adrift&apos;s cable-connection UI</figcaption></figure><p>There are lots of different ways to write code that produces UI. If you were going to start from first principles, which I did for Adrift, you might start out writing code that computes the location of each character directly, something like this:</p><pre><code>left = 10
top = 10
drawCharacter(left, top, &quot;|&quot;)
drawString(left + 1, top, &quot;Inventory&quot;)
top += 1
for (item in items) {
  drawCharacter(left, top, &quot;|&quot;)
  drawString(left + 1, top, item.name)
  top += 1
}</code></pre><p>Keeping track of the precise location where each character should be placed quickly becomes cumbersome. It&apos;s really easy to mess up the calculations for what should go where, and it&apos;s hard to reorganize UI that&apos;s written like this. Not to say this style of UI code can&apos;t be perfectly serviceable&#x2014;most of NetHack&apos;s UI code is written this way, <a href="https://github.com/NetHack/NetHack/blob/1e1d58033640254cb5e8a83d553d3c899583f768/win/curses/cursstat.c#L1928">for example</a>, and <a href="https://github.com/CleverRaven/Cataclysm-DDA/blob/272a1d424443a9501fea2b58d0ff4c9f6638b68d/src/advanced_inv.cpp#L231">Cataclysm: Dark Days Ahead</a> too! And you can achieve some nice idiosyncratic effects with it.</p><p>But: it seems like a lot of effort. I&apos;m time-poor, and I want the computer to help me with this. Enter UI layout algorithms. Instead of describing the specific location of each character on the screen, I&apos;d rather describe at a high level the relationships that different parts of the UI have with each other, and then let the computer figure out where precisely to draw everything. For instance, I might express the above snippet like this:</p><pre><code>widget = BorderLeft(
  Column(
    Text(&apos;Inventory&apos;),
    items.map(item =&gt;
      Text(item.name)
    )
  )
)
draw(widget, 10, 10)</code></pre><p>I still specify the location on the screen of the top-left corner, but everything else is the computer&apos;s problem.</p><p>How might we make a system that works like this? What kind of properties would we want this kind of system to have?</p><p>As previously covered, I&apos;m time-poor, so instead of coming up with this system from scratch myself, I decided to copy someone else&apos;s. The first thought I had was to look at tools like <a href="https://github.com/vadimdemedes/ink">Ink</a>, which bring something close to CSS&apos;s <a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">flexbox</a> to the terminal. Ink is based on <a href="https://yogalayout.com/">Yoga</a> under the hood, which reimplements the CSS flexbox algorithm in a cross-platform way. However: it&apos;s really complicated. The <a href="https://github.com/facebook/yoga/blob/master/yoga/Yoga.cpp">layout code</a> is nearly 5,000 lines of C++, not to mention bindings, and to use it I&apos;d have to bring in another native library. On top of that, Yoga isn&apos;t built with discrete grids like the console in mind: all its coordinates are floating-point numbers. It seemed like there was a simpler way.</p><p>But this got me thinking: what layout algorithms are out there? I&apos;ve already mentioned flexbox, and CSS also defines a <a href="https://www.w3.org/TR/css-grid-1/">grid</a> layout algorithm, among <a href="https://www.w3.org/TR/CSS2/tables.html">other</a> <a href="https://www.w3.org/TR/CSS2/visuren.html">layout</a> <a href="https://drafts.csswg.org/css-multicol-1/">algorithms</a>. But there&apos;s also <a href="https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/AutolayoutPG/index.html">Auto Layout</a>, which is a constraint-based system that uses linear programming under the hood, and <a href="https://flutter.dev/docs/resources/architectural-overview#layout-and-rendering">Flutter</a>, which uses a single-pass algorithm, and <a href="https://crystalminds.medium.com/introducing-the-swiftui-layout-system-part-i-the-basics-42083aaaa5c7">SwiftUI</a> which is similar, and <a href="https://developer.gnome.org/gtk4/stable/LayoutManagers.html">GTK</a> which has a whole bunch of <a href="https://blog.gtk.org/2019/03/27/layout-managers-in-gtk-4">different layout algorithms</a> (including <a href="https://blog.gtk.org/2019/07/02/constraint-layouts/">a constraint-based one like Auto Layout</a>), and so does <a href="https://doc.qt.io/qt-5/layout.html">Qt</a>. What a dizzying array of options! Which ones of these are good? Which are appropriate for building UI in roguelikes?</p><p>I don&apos;t know, but I was drawn to the simplicity of the SwiftUI/Flutter model. It seemed flexible and powerful while still being simple and fast. The two models are similar but Flutter is much better-documented, so that&apos;s the one I went with, and which I&apos;ll describe here.</p><p>Flutter calls its fundamental units of layout RenderObjects. There&apos;s some other stuff around this but RenderObjects are what do the actual layout, so I&apos;ll ignore the other stuff. The layout algorithm is as follows. Descending through the tree in a depth-first manner, each RenderObject:</p><ol><li>receives a minimum and maximum size from its parent,</li><li>lays out its children, passing down size constraint information, and then</li><li>picks a size for itself within the bounds given to it.</li></ol><p>Each RenderObject picks its own <em>size</em> (within the bounds given), but <em>offsets</em> are chosen by the parent. There&apos;s a more in-depth (but still really readable) <a href="https://flutter.dev/docs/resources/architectural-overview#layout-and-rendering">explanation in the Flutter documentation</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2021/05/image.png" class="kg-image" alt loading="lazy" width="2000" height="1046" srcset="https://blog.nornagon.net/content/images/size/w600/2021/05/image.png 600w, https://blog.nornagon.net/content/images/size/w1000/2021/05/image.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2021/05/image.png 1600w, https://blog.nornagon.net/content/images/2021/05/image.png 2013w" sizes="(min-width: 720px) 720px"><figcaption>Constraints are passed down the tree, sizes are returned up the tree.</figcaption></figure><p>This is a single-pass layout algorithm. Once the algorithm is complete, every RenderObject has a size and offset, and a second pass is done to paint the UI onto the screen.</p><p>This turned out to be really easy to implement! This is the structure, roughly speaking:</p><pre><code class="language-java">interface Constraints {
  int minWidth();
  int maxWidth();
  int minHeight();
  int maxHeight();
}

interface RenderObject {
  void layout(Constraints constraints);
  void paint(PaintContext context, Offset offset);
  Size size();
}</code></pre><p>Now, this RenderBox interface doesn&apos;t by itself do any kind of layout&#x2014;it&apos;s not even a tree!&#x2014;it just provides the structure for the algorithm. This is where the power of this approach comes in: you can write any layout logic you want as long as it follows this structure! You could even have a nested RenderObject that lays its own children out using a completely different algorithm, as long as the total final size obeys the constraints that were passed to it.</p><p>As an example, a BorderLeft RenderObject might look like this:</p><pre><code>class BorderLeft implements RenderObject {
  private RenderObject child;
  BorderLeft(RenderObject child) { this.child = child; }

  void layout(Constraints constraints) {
    // Since we&apos;re going to be 1 character wider than our child,
    // ask it to make itself be 1 narrower than we were asked to be.
    Constraints childConstraints = new Constraints(
      /* minWidth = */ constraints.minWidth - 1,
      /* maxWidth = */ constraints.maxWidth - 1,
      /* minHeight = */ constraints.minHeight,
      /* maxHeight = */ constraints.maxHeight,
    );
    child.layout(childConstraints);
  }
  
  Size size() {
    // We are always 1 wider than our child.
    return child.size().add(new Size(1, 0));
  }
  
  void paint(PaintContext context, Offset offset) {
    context.paintBorder(offset.x(), offset.y(), size().height());
    child.paint(context, offset.add(new Offset(1, 0));
  }
}</code></pre><p>This is composable with any other RenderObject, and will add a border to the left of it.</p><p>There are lots of kinds of useful, generic, reusable RenderObjects. For instance, an object that renders text can handle text wrapping based on the <code>maxWidth</code> that is given to it. A column object can lay out its children vertically on top of each other (or, for a more general tool, see for example the <a href="https://api.flutter.dev/flutter/widgets/Flex-class.html">Flex</a> widget in Flutter, that implements a simplified version of something like CSS flexbox).</p><p>I built this system into Adrift and I&apos;ve converted all the UI code over to it. I&apos;ve been liking it a lot! Maybe you would like it too? Give it a try and <a href="https://twitter.com/nornagon">let me know</a> how it goes!</p>]]></content:encoded></item><item><title><![CDATA[Terrain generation in Minecraft]]></title><description><![CDATA[<p>The procedural terrain generation in Minecraft produces stunning results, and the worlds it creates have captivated millions. Underneath the hood, it&apos;s actually a fairly straightforward algorithm driving all the complexity and variation in Minecraft&apos;s infinite worlds. In this post I&apos;m going to break down</p>]]></description><link>https://blog.nornagon.net/terrain-generation-in-minecraft/</link><guid isPermaLink="false">5f6432f70e00440001902023</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sun, 09 May 2021 04:28:33 GMT</pubDate><media:content url="https://blog.nornagon.net/content/images/2021/05/1.-noise-2.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.nornagon.net/content/images/2021/05/1.-noise-2.png" alt="Terrain generation in Minecraft"><p>The procedural terrain generation in Minecraft produces stunning results, and the worlds it creates have captivated millions. Underneath the hood, it&apos;s actually a fairly straightforward algorithm driving all the complexity and variation in Minecraft&apos;s infinite worlds. In this post I&apos;m going to break down how one important stage in Minecraft&apos;s terrain generation works.</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.06.33.png" width="854" height="480" loading="lazy" alt="Terrain generation in Minecraft" srcset="https://blog.nornagon.net/content/images/size/w600/2020/09/2020-09-26_10.06.33.png 600w, https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.06.33.png 854w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.07.07.png" width="854" height="480" loading="lazy" alt="Terrain generation in Minecraft" srcset="https://blog.nornagon.net/content/images/size/w600/2020/09/2020-09-26_10.07.07.png 600w, https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.07.07.png 854w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.11.55.png" width="854" height="480" loading="lazy" alt="Terrain generation in Minecraft" srcset="https://blog.nornagon.net/content/images/size/w600/2020/09/2020-09-26_10.11.55.png 600w, https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.11.55.png 854w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.14.56.png" width="854" height="480" loading="lazy" alt="Terrain generation in Minecraft" srcset="https://blog.nornagon.net/content/images/size/w600/2020/09/2020-09-26_10.14.56.png 600w, https://blog.nornagon.net/content/images/2020/09/2020-09-26_10.14.56.png 854w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Some gorgeous Minecraft terrain made even prettier by the <a href="https://bitslablab.com/">BSL shader pack</a>.</figcaption></figure><p>Broadly, generating terrain in Minecraft happens in five stages: first, a biome map is generated. Then, chunk-by-chunk, the sky is divided from the earth. Third, the stone surface is replaced with dirt. Fourth, caves and canyons are carved. And finally, ore is planted and trees and grass spring forth.</p><!--kg-card-begin: html--><figure class="kg-card kg-card-hascaption"><div style="display: flex; justify-content: center; align-items: flex-end; overflow: hidden; height: 600px;">
    <video loop width="1024" height="768" autoplay muted>

<source src="https://blog.nornagon.net/content/images/2020/09/minecraft-chunkgen.webm" type="video/webm">

Sorry, your browser doesn&apos;t support embedded videos.
</video>
    </div><figcaption>The four stages after biomes are generated: (1) noise, (2) surface, (3) carvers, (4) features.</figcaption></figure><!--kg-card-end: html--><p>Each of these stages would take an entire blog post to describe. In this post I specifically want to describe the first step after biomes are generated&#x2014;the stage I&apos;ve called &quot;noise&quot; above. The noise stage is when Minecraft decides which blocks are solid and which are air. The other parts of the process are interesting too, but I&apos;m trying to create a Minecraft world type which has a lot of floating islands above an ocean, so I really want to understand how to manipulate the way the algorithm places solid blocks.</p><p>In Minecraft 1.16, there&apos;s a new (still experimental) way to tweak the terrain generation parameters using a data pack. In 1.12, most of these parameters were tweakable by creating a &quot;custom&quot; world, but 1.16 gives much finer control, which is super exciting. You can see the vanilla worldgen parameters for 1.16 <a href="https://github.com/slicedlime/examples">on slicedlime&apos;s GitHub page</a> (or unpacked for your viewing pleasure <a href="https://github.com/misode/vanilla-worldgen">here</a>). The bits that affect the &quot;noise&quot; step are under <code><a href="https://github.com/misode/vanilla-worldgen/tree/master/worldgen/noise_settings">worldgen/noise_settings</a></code>, one file per noise preset type.</p><p>Here&apos;s an example from the <a href="https://github.com/misode/vanilla-worldgen/blob/master/worldgen/noise_settings/overworld.json">vanilla Overworld settings</a>. The noise settings also include information about structures, which I&apos;m not diving into in this post, so here are just the bits that are relevant for the noise step:</p><pre><code class="language-json">{
  &quot;noise&quot;: {
    &quot;height&quot;: 256,
    &quot;size_horizontal&quot;: 1,
    &quot;size_vertical&quot;: 2,

    &quot;sampling&quot;: {
      &quot;xz_scale&quot;: 0.9999999814507745,
      &quot;y_scale&quot;: 0.9999999814507745,
      &quot;xz_factor&quot;: 80.0,
      &quot;y_factor&quot;: 160.0
    },

    &quot;density_factor&quot;: 1.0,
    &quot;density_offset&quot;: -0.46875,
    &quot;random_density_offset&quot;: true,

    &quot;bottom_slide&quot;: {
      &quot;target&quot;: -30,
      &quot;size&quot;: 0,
      &quot;offset&quot;: 0
    },
    &quot;top_slide&quot;: {
      &quot;target&quot;: -10,
      &quot;size&quot;: 3,
      &quot;offset&quot;: 0
    }
  },
  ...
}</code></pre><p>I&apos;m going to explain how each of these parameters affects the way the terrain is generated. These parameters only affect how Minecraft chooses which blocks are solid and which are not-solid (i.e. air, or water if below sea level). They don&apos;t affect which blocks are placed in the world in the end&#x2014;initially, all the solid blocks are set to stone.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/11/1.-noise-2.png" class="kg-image" alt="Terrain generation in Minecraft" loading="lazy" width="1024" height="768" srcset="https://blog.nornagon.net/content/images/size/w600/2020/11/1.-noise-2.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/11/1.-noise-2.png 1000w, https://blog.nornagon.net/content/images/2020/11/1.-noise-2.png 1024w" sizes="(min-width: 720px) 720px"><figcaption>A chunk after the noise step is completed.</figcaption></figure><p>The noise step happens on a chunk-by-chunk basis, where each chunk (16x16 block column) is generated separately. The edges still line up, even though the chunks are generated separately, because Minecraft uses simplex noise. More on that later.</p><p>When deciding which blocks in a chunk should be solid and which should be non-solid, Minecraft first is generates a noise pattern, where it gets all the randomness. Then it modifies the noise values to make the sky mostly empty and the ground mostly solid, and also to vary the height according to the biome, as well as gracefully forcing the very top blocks in the world to be empty, and the very bottom blocks to be solid. Happily, all these steps are very configurable in Minecraft 1.16!</p><h2 id="noise-sampling">Noise sampling</h2><p>Relevant parameters: <code>xz_scale</code>, <code>y_scale</code>, <code>xz_factor</code>, <code>y_factor</code>, <code>size_horizontal</code>, <code>size_vertical</code>.</p><h3 id="simplex-noise-octaves-and-range-noise">Simplex noise, octaves, and range noise</h3><p>Minecraft uses 3D simplex noise to generate its terrain. Simplex noise is an algorithm which lets you sample a smoothly-changing random value anywhere in space, without having to pre-generate anything. It&apos;s useful for Minecraft particularly because of its ability to continue infinitely in all directions. Minecraft uses simplex noise in a very particular and somewhat unusual way.</p><p>First, it uses 16 octaves of noise. This isn&apos;t the unusual part. &quot;Octaves&quot; is a fancy word meaning it generates many different simplex noise fields at different scales and adds them together.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/11/Simplex-noise---octaves--3-.png" class="kg-image" alt="Terrain generation in Minecraft" loading="lazy" width="2000" height="301" srcset="https://blog.nornagon.net/content/images/size/w600/2020/11/Simplex-noise---octaves--3-.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/11/Simplex-noise---octaves--3-.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2020/11/Simplex-noise---octaves--3-.png 1600w, https://blog.nornagon.net/content/images/2020/11/Simplex-noise---octaves--3-.png 2076w" sizes="(min-width: 1200px) 1200px"><figcaption>The more octaves you add together, the more fine detail you get.</figcaption></figure><p>Second, it uses <em>three sets of octaves</em>. That&apos;s three separate noise fields, each composed of 16 octaves, that get combined together to produce a final field. Two of those fields define a &quot;lower&quot; and &quot;upper&quot; value at each point in space, and the third field defines a sliding value within that range. This is the bit that&apos;s unusual. I&apos;m not sure it has a name, but I call it <em>range noise</em>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/12/Range-noise--2-.png" class="kg-image" alt="Terrain generation in Minecraft" loading="lazy" width="1394" height="476" srcset="https://blog.nornagon.net/content/images/size/w600/2020/12/Range-noise--2-.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/12/Range-noise--2-.png 1000w, https://blog.nornagon.net/content/images/2020/12/Range-noise--2-.png 1394w" sizes="(min-width: 720px) 720px"><figcaption>Range noise crossfades between two different noise patterns (&quot;upper&quot; and &quot;lower&quot;) based on the value of a third noise pattern (&quot;main&quot;) to produce a rougher final output.</figcaption></figure><p>Range noise creates a sort of &quot;punctuated equilibrium&quot;, areas of smooth slow change interrupted occasionally by dramatic shifts. It helps the terrain to look more interesting and dynamic than just using plain simplex noise.</p><h3 id="subsampling">Subsampling</h3><p>Ultimately, all these noise calculations define a <em>density grid</em>. The density grid is a 16&#x2A09;16&#x2A09;256 3D grid which has a number for each block in the chunk. If that number is positive, the block will be set as solid. If the number is negative, the block will be set as air (or water if it&apos;s below sea level). Each block in the density grid is filled with a number by sampling a value from the noise generator at the (<em>x</em>, <em>y</em>, <em>z</em>) coordinate of the block. The way simplex noise works is that if you sample the same (<em>x</em>, <em>y</em>, <em>z</em>) coordinate multiple times you&apos;ll always get the same number back. That&apos;s why chunks can be generated independently of one another.</p><p>Actually, I lied a bit&#x2014;the size of the density grid is smaller than 16&#x2A09;16&#x2A09;256. To reduce the number of noise calculations that need to be done, Minecraft generates the density grid at a smaller size, then blows it up. Imagine generating a small 2D image and then resizing it to be bigger. That&apos;s what the <code>size_horizontal</code> and <code>size_vertical</code> parameters do, but in 3D. The name &quot;size&quot; is a bit misleading though, as increasing these parameters actually makes the density grid <em>smaller</em>. For instance, if the <code>height</code> is 256, and the <code>size_vertical</code> parameter is 2, then the density grid will be 128 blocks tall. Well, actually, I lied again&#x2014;internally, Minecraft multiplies both of these size parameters by 4, so the density grid would be 64 blocks tall in this case. These parameters can be set to 1, 2 or 4. With the internal multiplication, that means the possible values are 4, 8 or 16. Technically you can also set it to 3, but that results in odd glitchy terrain because 12 doesn&apos;t evenly divide 16.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/12/Subsampled-noise--1-.png" class="kg-image" alt="Terrain generation in Minecraft" loading="lazy" width="1100" height="312" srcset="https://blog.nornagon.net/content/images/size/w600/2020/12/Subsampled-noise--1-.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/12/Subsampled-noise--1-.png 1000w, https://blog.nornagon.net/content/images/2020/12/Subsampled-noise--1-.png 1100w" sizes="(min-width: 720px) 720px"><figcaption>As the size parameter increases, the number of points in the density grid gets smaller, and the noise gets smoother and less detailed. A size parameter of <em>n</em> means only every <em>n</em>th point in the noise field is sampled, and the in-between points get smoothly interpolated.</figcaption></figure><h3 id="scale-and-factor">Scale and factor</h3><p>The <code>xz_scale</code>, <code>y_scale</code>, <code>xz_factor</code> and <code>y_factor</code> parameters control how the simplex noise is sampled. These parameters can have a huge effect on how the generated landscape feels. The <code>scale</code> parameters control the upper and lower boundary noise fields in the range noise, while the <code>factor</code> parameters control the &quot;main&quot; noise which controls the crossfade between the upper and lower noise fields. All these parameters affect &quot;zoomed out&quot; the noise is.</p><p>For <code>xz_scale</code> and <code>y_scale</code>, which control the two boundaries of the range noise, a higher value means a more &quot;zoomed out&quot; noise&#x2014;the landscape will be fuzzier, and features like mountains and valleys will be smaller. A lower value means a more &quot;zoomed in&quot; noise&#x2014;the landscape will be smoother, and features will be larger. The parameters which control the main noise (which controls the crossfade between the two boundaries) <code>xz_factor</code> and <code>y_factor</code> are inverted, so higher values mean more zoomed in, smoother variation and lower values mean more zoomed out, fuzzy noise.</p><p>The vanilla overworld uses scale values very close to 1 for both <code>xz_scale</code> and <code>y_scale</code>, so using values higher than 1 means your world will be fuzzier than the vanilla overworld, and using values lower than 1 means your world will be smoother than the vanilla overworld. The range for all these parameters is between 0.001 and 1000.</p><h2 id="density-modification">Density modification</h2><p>Relevant parameters: <code>density_factor</code>, <code>density_offset</code>.</p><h3 id="density-factor-and-offset">Density factor and offset</h3><p>Before the density grid gets turned into blocks, it&apos;s modified by two parameters: the <em>density factor</em> and the <em>density offset</em>. These modifiers are applied after the density grid is generated from the simplex noise field. This step is also where biome-based height variation happens&#x2014;this is where mountains are made.</p><p>The density factor is what divides vertical space into &quot;land&quot; and &quot;sky&quot;. It skews the density grid positive (solid) towards y=0 and negative (air) towards y=256. The density factor is a multiplier on this skew. So a density factor of 0.0 means no skewing is done at all and there&apos;s no division between land and sky&#x2014;the Nether, for example, uses a density factor of 0.0. A density factor greater than 0 will skew the density grid towards solid below halfway up the chunk, and towards air above halfway up the chunk. This is what the overworld does&#x2014;solid blocks go at the bottom, air goes at the top. A negative density factor would invert that, skewing the lower half of the chunk towards air and the upper half of the chunk towards solid.</p><!--kg-card-begin: html--><figure class="kg-card kg-card-hascaption"><div style="display: flex; justify-content: center;">
    <video loop width="128" height="256" autoplay muted>

<source src="https://blog.nornagon.net/content/images/2020/09/minecraft-density_factor.webm" type="video/webm">

Sorry, your browser doesn&apos;t support embedded videos.
</video>
    </div><figcaption>The density factor applies a gradient to the density grid. When the density factor is 0.0, there is no difference between the top of the chunk and the bottom of the chunk. As the density factor increases, ground level becomes more defined.</figcaption></figure><!--kg-card-end: html--><p>The density offset is a flat value that gets added to all densities in the field. A higher density offset will make every block more likely to be solid. A lower (or negative) density offset will make every block more likely to be air. This has the effect of raising or lowering the average height of the land (assuming the density factor is positive), so a higher density offset will get you mountains or plateaus.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/12/default_2020-11-24_21-52-48-200-3.png" class="kg-image" alt="Terrain generation in Minecraft" loading="lazy" width="1837" height="1536" srcset="https://blog.nornagon.net/content/images/size/w600/2020/12/default_2020-11-24_21-52-48-200-3.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/12/default_2020-11-24_21-52-48-200-3.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2020/12/default_2020-11-24_21-52-48-200-3.png 1600w, https://blog.nornagon.net/content/images/2020/12/default_2020-11-24_21-52-48-200-3.png 1837w" sizes="(min-width: 720px) 720px"><figcaption>The same chunk, but generated with a varying density factor. The version in the center has a density factor of 0.0. The versions on the left have decreasing (negative) density factor. The versions on the right have increasing (positive) density factor.</figcaption></figure><h3 id="slides">Slides</h3><p>Relevant parameters: <code>top_slide</code>, <code>bottom_slide</code>.</p><p>The last step that happens before turning the density grid into solid blocks is applying the <em>slides</em>. There are two slides: the top slide and the bottom slide. They do the same thing, but one is applied at the top of the chunk and the other at the bottom.</p><p>The slides force the value of the density grid towards a certain desired target value the closer to the end of the range it gets. So, for example, for a top slide target value of &#x2013;30, as you get closer to the top of the chunk, the density would be pushed closer and closer to &#x2013;30 until at the very top the value of the density grid is forced to be &#x2013;30 (i.e. air).</p><hr><p>There&apos;s plenty more to Minecraft terrain generation&#x2014;I didn&apos;t cover caves, or biome placement, or decorations&#x2014;but if you&apos;re interested in playing around with how the base land is generated, I hope this post helped you understand the underlying systems!</p>]]></content:encoded></item><item><title><![CDATA[Adrift map generation: WFC for rooms]]></title><description><![CDATA[<p>In my <a href="https://blog.nornagon.net/adrift-map-generation-binary-space-partitioning/">last post</a> on Adrift&apos;s map generation, I noted that the binary space partitioning technique that Adrift uses produces arbitrarily-sized rectangles for rooms. Generating the contents of rooms that aren&apos;t a standard shape is a bit of a challenge. Games like NetHack and Cogmind get</p>]]></description><link>https://blog.nornagon.net/adrift-wfc-for-room-generation/</link><guid isPermaLink="false">5ed19a35695cb1000152d53b</guid><category><![CDATA[Adrift]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sat, 30 May 2020 16:52:49 GMT</pubDate><content:encoded><![CDATA[<p>In my <a href="https://blog.nornagon.net/adrift-map-generation-binary-space-partitioning/">last post</a> on Adrift&apos;s map generation, I noted that the binary space partitioning technique that Adrift uses produces arbitrarily-sized rectangles for rooms. Generating the contents of rooms that aren&apos;t a standard shape is a bit of a challenge. Games like NetHack and Cogmind get around this by having very lightly-furnished rooms with 1-tile items. Brogue has a very interesting approach that helps it to produce &quot;tactically interesting&quot; rooms (Brian Walker gave an <a href="https://www.youtube.com/watch?v=Uo9-IcHhq_w">excellent talk</a> about it at RogueCel 2018). In this post, I&apos;ll talk about one of the techniques Adrift uses to generate room contents: <a href="https://github.com/mxgmn/WaveFunctionCollapse">wave function collapse</a>.</p><p>I&apos;m not going to give a complete overview of the wave function collapse algorithm, because <a href="https://github.com/mxgmn/WaveFunctionCollapse#notable-ports-forks-and-spinoffs">many others</a> have done a great job of that already. If you haven&apos;t encountered the algorithm before, I&apos;d recommend taking a moment to read a little about it and take a look at <a href="https://twitter.com/OskSta/status/787319655648100352">some</a> <a href="https://twitter.com/OskSta/status/784847588893814785">of</a> <a href="https://twitter.com/mewo2/status/789167437518217216">the</a> <a href="https://twitter.com/ExUtumno/status/895684431477747715">things</a> <a href="https://marian42.itch.io/wfc">other</a> <a href="https://twitter.com/voorbeeld/status/1073874337248239616">folks</a> have done with it. It&apos;s an impressively flexible algorithm!</p><p>Adrift uses a variation on the wave function collapse algorithm, implemented using a constraint solver, to generate different kinds of rooms in arbitrary shapes. These are the sorts of things it can produce:</p><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.41.56-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.41.56-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.41.56-PM.png 968w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.19-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.42.19-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.19-PM.png 968w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.25-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.42.25-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.25-PM.png 968w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.32-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.42.32-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.42.32-PM.png 968w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Four examples of generated crew quarters rooms.</figcaption></figure><figure class="kg-card kg-gallery-card kg-width-wide kg-card-hascaption"><div class="kg-gallery-container"><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.12-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.47.12-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.12-PM.png 968w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.18-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.47.18-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.18-PM.png 968w" sizes="(min-width: 720px) 720px"></div></div><div class="kg-gallery-row"><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.42-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.47.42-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.47.42-PM.png 968w" sizes="(min-width: 720px) 720px"></div><div class="kg-gallery-image"><img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.48.09-PM.png" width="968" height="886" loading="lazy" alt srcset="https://blog.nornagon.net/content/images/size/w600/2020/05/Screen-Shot-2020-05-29-at-4.48.09-PM.png 600w, https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-29-at-4.48.09-PM.png 968w" sizes="(min-width: 720px) 720px"></div></div></div><figcaption>Four examples of generated break rooms.</figcaption></figure><p>So far the space partitioning algorithm that generates the room boundaries always generates rectangles, but this approach for generating room contents can handle rooms of any shape.</p><h2 id="so-how-does-that-work-then">So how does that work, then?</h2><p>The idea is that each room is assembled by solving a jigsaw puzzle with a bunch of pieces of different sizes, where each piece can only match certain other pieces. So we have a bunch of jigsaw pieces with differently-shaped edges, and we try out placing them next to each other until we get an arrangement where all the edges match.</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/2020/05/image-11.png" class="kg-image" alt loading="lazy"></figure><p>Each jigsaw piece defines a little chunk of the room that makes sense for the type of room being generated: in the break room, the pieces might be a couch, a table and chairs with a pack of cards, a TV by the wall, a bar with stools and a refrigerator. In the infirmary the pieces might be a gurney, a medicine cabinet, an oxygen tank, and so on. To assemble a room, all we have to do is solve the puzzle. Unlike a regular jigsaw puzzle though, there are many possible ways of connecting the pieces together. We&apos;re not aiming for a particular final room, just <em>any</em> arrangement of the pieces where the pieces fit together.</p><p>Adrift&apos;s architecture is <a href="https://blog.nornagon.net/adrift-fragments/#data-with-a-soul">heavily data-driven</a>, and these room piece definitions are no different. For example, here&apos;s the current set of parts for the break rooms, snipped directly from the YAML data that drives the game:</p><pre><code class="language-YAML">- type: roomgen
  name: lounge
  algorithm: WFC
  options:
    parts:
      # empty space is allowed anywhere
      - |
        ***
        *.*
        ***

      # a sofa next to the wall
      - |
        xxxxx
        *hhh*
        *...*

      # a TV on the wall with some space next to it
      - |
        xxxxx
        *.D.*
        *...*

      # a bar with a refrigerator and some stools
      - |
        xxxxxxx
        *....R*
        *=====*
        *.s.s.*
        *.....*

      # chairs and tables
      - |
        *****
        *.c.*
        *.Tc*
        *...*
        *****
      - |
        *****
        *.c.*
        *.T.*
        *.c.*
        *****

      # heating vent
      - max: 1
        part: |
          xxx
          *V*
          *.*

      # replicator
      - max: 1
        part: |
          xxx
          *P*
          *.*</code></pre><p>Each part defines a jigsaw piece. The characters around the edges of the piece define what will match there: <code>x</code> meaning the edge of the room, <code>*</code> meaning anything, and other characters matching those characters. So the first piece, a <code>.</code> with <code>*</code> surrounding it, is defining a 1x1 piece that can match anything on its four edges. The second piece, the sofa, is a 3x1 piece, and will only match the room&apos;s edge on its top side, and floor on its bottom side. The engine also automatically generates flipped and rotated versions of each piece, so the sofa could also appear on the left/right/bottom walls as well as the top.</p><p>The job of the room generator is to assemble these pieces into a room such that each piece is placed next to something that matches it, and every spot in the room is covered. For this, Adrift uses a constraint solver. If you&apos;re familiar with WFC, this is similar to the &quot;simple tiled&quot; model in WFC.</p><!--kg-card-begin: html--><figure class="kg-card kg-card-hascaption"><div style="text-align: center">
    <video controls width="256">

<source src="https://blog.nornagon.net/content/images/2020/05/lounge-wfc.mp4" type="video/mp4">

Sorry, your browser doesn&apos;t support embedded videos.
</video>
    </div><figcaption>This shows the constraint solver in action, one frame per decision. The different colors represent cells belonging to different parts from the definition.</figcaption></figure><!--kg-card-end: html--><h2 id="wave-function-collapse-is-constraint-solving">Wave Function Collapse is Constraint Solving</h2><p>At its heart, <a href="https://adamsmith.as/papers/wfc_is_constraint_solving_in_the_wild.pdf">the WFC algorithm is a simplified constraint solver</a>. The vanilla WFC algorithm has no backtracking, though, and relies on an entropy-based heuristic to guide its search towards a satisfactory solution (i.e. one which has no mismatched edges between pieces). This is roughly similar to the &quot;<a href="https://ktiml.mff.cuni.cz/~bartak/constraints/ordering.html">first-fail</a>&quot; heuristic which common in constraint solvers, where the solver chooses the next variable to try setting based on which has the smallest number of possible values remaining (<a href="https://dl.acm.org/doi/pdf/10.1145/321296.321300#page=7">proposed as early as 1965</a>!). There&apos;s some subtlety in the way that noise is applied to entropy values in WFC that I have thus far ignored, but the results still seem pretty good even without taking that into account.</p><p>Formulating WFC as a constraint program and using a constraint solver rather than using a dedicated WFC algorithm gives us two advantages:</p><ol><li>We get intelligent backtracking for free, and</li><li>We can impose generalized constraints on top of the inherent tile-adjacency constraints that WFC enforces.</li></ol><p>You might have noticed the <code>max: 1</code> annotation in the YAML above, which stipulates that at most 1 copy of that tile can be placed in the final room. (Adrift also supports a <code>min</code> count.) Vanilla WFC cannot accommodate this kind of constraint, but since we&apos;re using a full-blown constraint solver, it&apos;s relatively straightforward to add. I&apos;ve also been able to add reachability constraints that prevent the solver from generating maps with unreachable sections. Adrift uses <a href="https://choco-solver.org/">Choco</a> as its constraint solver, though I also recommend <a href="https://developers.google.com/optimization/cp/cp_solver">or-tools</a> for this kind of work&#x2014;it has Python, C++ and Java bindings.</p><p>Constraint solvers only speak in integers, so in order to explain to the solver how to generate a map, we need to translate the task into its language. For generating rooms, we translate each cell in the grid as an integer variable with a range between 0 and <em>n</em>, where <em>n</em> is the number of possible ways a cell could be assigned (including rotation and flipping). So we have <em>w</em> &#x2A09; <em>h</em> integer variables. Then, we add in a constraint between each pair of horizontally adjacent variables, specifying the legal assignments of the pair. For example, if tile <em>i</em> can fit to the left of tile <em>j</em>, then (<em>i</em>, <em>j</em>) is a legal assignment of a pair of variables that are horizontally adjacent. Similarly for the vertically adjacent pairs. This tells the solver that it&apos;s only allowed to assign values to variables when they match their neighbors.</p><p>A note about the room pieces that are larger than 1x1: to explain these to the solver, we break each larger piece up into 1x1 sub-pieces, each of which can only match the appropriate sub-pieces from the same parent piece on its edges.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-12.png" class="kg-image" alt loading="lazy"><figcaption>Breaking up a larger part into subparts with keyed edges. The internal edges will only match the opposite internal edges from its sibling subparts.</figcaption></figure><h2 id="one-of-many">One of many</h2><p>WFC, even with the additional power we get from using a full constraint solver, won&apos;t be a fit for every kind of room we want to generate in Adrift. That&apos;s why the data format allows for specifying different room generation algorithms, with options specific to the algorithm. In future, it might also turn out to be useful to be able to &apos;layer&apos; room generation algorithms, first running WFC or another algorithm to generate the base furniture, and then running further algorithms to modify the results of the first algorithm&#x2014;for example, adding trash to the room, or growing plants in it, or moving some of the furniture around.</p><p>That said, I&apos;ve been happy with the quality and variety of the results so far, and I think there&apos;s a lot more I can get out of the algorithm by carefully authoring room pieces, and constraining it in interesting ways.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-10.png" class="kg-image" alt loading="lazy"><figcaption>A few of the WFC-generated rooms generated in the game.</figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Adrift: Fragments]]></title><description><![CDATA[<p><em><em>You wake up alone on a broken colony ship. You&apos;re starving hungry&#x2014;how long were you asleep?&#x2014;but the door won&apos;t open. You&apos;ll need your wits about you to take apart, diagnose and repair the ship&apos;s limping systems, stay alive,</em></em></p>]]></description><link>https://blog.nornagon.net/adrift-fragments/</link><guid isPermaLink="false">5ec9c4e5ee24ec0001420495</guid><category><![CDATA[Adrift]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sun, 24 May 2020 03:43:05 GMT</pubDate><content:encoded><![CDATA[<p><em><em>You wake up alone on a broken colony ship. You&apos;re starving hungry&#x2014;how long were you asleep?&#x2014;but the door won&apos;t open. You&apos;ll need your wits about you to take apart, diagnose and repair the ship&apos;s limping systems, stay alive, and figure out what the hell happened.</em></em></p><p>I was looking back through posts I&apos;ve made about Adrift on the <a href="https://reddit.com/r/roguelikedev">r/roguelikedev</a> subreddit about Adrift over the last year or so and I found some cool stuff that I&apos;d written, so I wanted to collect it in one place so it&apos;s more easily linkable. There&apos;s no real theme here other than &quot;things I&apos;ve thought about Adrift&quot;.</p><p>If you&apos;ve not heard me talk your ear off about Adrift already, this is probably the best place as of writing to understand more about what kind of game it is I&apos;m trying to make. The fragments are in chronological order, so the later parts are closer to the current state of the game.</p><h2 id="rexpaint-mockups">REXPaint Mockups</h2><p>I did a few <a href="https://www.reddit.com/r/roguelikedev/comments/9lrhfm/sharing_saturday_227/e7esmd3/">mockups</a> in <a href="https://www.gridsagegames.com/rexpaint/">REXPaint</a> after seeing <a href="https://www.gridsagegames.com/blog/2018/10/how-to-make-a-roguelike/">Kyzrati&apos;s talk at Roguelike Celebration 2018</a> and having my excitement about developing Adrift rekindled. These mockups are still pretty close to how I want the game to feel, though I no longer like the RPG-style dialog box.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/kTb0HYv.gif" class="kg-image" alt loading="lazy"><figcaption>Waking up in the cryopods.</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/TR7Dy4g-1.png" class="kg-image" alt loading="lazy"><figcaption>Something&apos;s wrong in the ponic farms.</figcaption></figure><h2 id="map-generation">Map generation</h2><p>I <a href="https://www.reddit.com/r/roguelikedev/comments/9nph2v/sharing_saturday_228/e7rkk09/">wrote a little</a> about what I&apos;m going for with map generation:</p><blockquote>Adrift has some unique map generation requirements which make it difficult to reuse ideas from other roguelikes. First, the map has to be completely filled. It doesn&apos;t make sense for there to be empty space on a spaceship like it does in a dungeon. So every single tile on the map must have a purpose. Second, the map should feel designed, but still unpredictable. A spaceship is a carefully constructed artifact, and the map should follow some kind of discernible logic, while keeping it interesting to replay and focusing on responding to the situation rather than memorizing a premade map.</blockquote><p>This still holds true.</p><blockquote>My theory at the moment is that constraint programming is a good toolset for generating these sorts of maps. With a constraint solver you can set up variables (e.g. what kind of room is this? Which walls have doors?) and then constrain the values of those variables so that only certain combinations are allowed. I&apos;ve been using <a href="https://github.com/chocoteam/choco-solver" rel="noopener nofollow ugc">choco-solver</a>, and this week I discovered the <a href="https://github.com/chocoteam/choco-graph" rel="noopener nofollow ugc">choco-graph</a> extension, which allows enforcing constraints like &quot;every room on the map must be reachable&quot;, which was a huge breakthrough for this technique.<br><br>I&apos;m dividing the world into 5x5 rooms, and the solver operates at the level of the room, not individual tiles. For each room slot, the solver chooses what type of room will go there, and then enforces that the adjacent rooms have to match the kind of walls that the just-placed room has. It keeps going like that until the whole map is full, at which point it return the completed map, or until it runs into a contradiction, which will cause the solver to backtrack and try a different placement. The algorithm is very similar to <a href="https://github.com/mxgmn/WaveFunctionCollapse" rel="noopener nofollow ugc">Wave Function Collapse</a>, but with the added ability to backtrack, and better ability to enforce global constraints such as &quot;connectedness&quot;.<br><br>The maps still feel pretty random and messy, though, not &quot;designed&quot;. I think some additional constraints will be able to help push the map towards a more designed feeling, such as enforcing some kinds of symmetry in local areas, and restricting how corridors can be placed to avoid corridors that just open out into other corridors and similar nonsensical layouts.</blockquote><p>I&apos;ve since played fairly extensively with this approach this and haven&apos;t found success with it. But <a href="https://blog.nornagon.net/adrift-map-generation-binary-space-partitioning/">BSP is working great</a>, and I&apos;ll be able to reuse the constraint programming stuff elsewhere, I think.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-1.png" class="kg-image" alt loading="lazy"><figcaption>Early output from the constraint-based map generation approach.</figcaption></figure><h2 id="data-with-a-soul">Data with a soul</h2><p>I <a href="https://www.reddit.com/r/roguelikedev/comments/9ppdfe/sharing_saturday_229/e85vpog/">wrote about data-driven design</a> early on, and Adrift continues to be a very data-driven design, with the vast majority of content being specified in YAML files.</p><blockquote>This week I moved all the info about items, terrain, furniture and so on out of hard-coded Scala and into YAML files. I really like Brian Buckelew&apos;s theory that <a href="https://www.youtube.com/watch?v=U03XXzcThGU" rel="noopener nofollow ugc">stories are just data with a soul</a>, and I&apos;ve seen data-driven development be a huge acceleration boost for games like <a href="https://cataclysmdda.org/" rel="noopener nofollow ugc">Cataclysm</a>, and I want to do that too. I reused some code from another project for parsing and sampling item-generation tables from JSON/YAML, so it was nice to not have to reinvent that.<br><br>I implemented room prefabs in the map generator, all defined in YAML, so now it&apos;s super easy to add new rooms and variations, and fill them with stuff. I didn&apos;t get to spend much time on actually creating them though, the game&apos;s still in a very early state and I&apos;m trying to get all the systems in minimal working order before filling out too much content.</blockquote><p>I&apos;ve since evolved my opinion on YAML, specifically, as a data format. Here&apos;s my opinion: YAML sucks. But it sucks much less than having to write a custom editor.</p><p>I&apos;ll probably not put anything into the game that would require me to write a custom editor. If I can&apos;t figure out a way to express some data I need as YAML, I&apos;ll cut that feature. Building a custom editor is just too much work for an already extremely ambitious project (compared to the amount of time I have available to dedicate to it).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-2.png" class="kg-image" alt loading="lazy"><figcaption>There are now rooms with stuff in them!</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-3.png" class="kg-image" alt loading="lazy"><figcaption>You can take the stuff apart!</figcaption></figure><blockquote>I had a small epiphany this evening chatting to Nato about storing items and their locations. Previously I&apos;ve found a lot of tension between having items responsible for knowing where they&apos;re located in the game (in a backpack? on the floor? worn?) and having locations be responsible for knowing what items they contain (e.g. a map cell having a list of items it contains). We were exploring some options and we hit on the idea from the world of databases: if all your items were in some sort of SQL database, you could query by item ID or item location, no problem. <code>SELECT * FROM items WHERE location = (32, 12)</code>.<br><br>I don&apos;t want to go full-blown SQL, but that idea was pretty neat, and it eventually lead me to a solution to the problem of whether to store item-locations on items or in locations. That is: <em><em>neither!</em></em> Instead, have a data structure separate from items and locations which stores the item-location pairing, and supports lookup by location or by item.</blockquote><p>I&apos;m still using this system and it&apos;s working great. Highly recommend.</p><h2 id="in-which-i-somehow-implemented-four-foundational-systems-while-packing-up-my-apartment">In which I somehow implemented four foundational systems while packing up my apartment</h2><p>Apparently I called this <a href="https://www.reddit.com/r/roguelikedev/comments/9rpy0z/sharing_saturday_230/e8ktpkd/">&quot;a short week&quot;</a>? But these systems are all fundamental to the game. Time is weird.</p><blockquote>The game <a href="https://imgur.com/XlEFfEz" rel="noopener nofollow ugc">now supports color</a>! Each category of items now has a foreground and background color from a palette, as well as a character. Eventually I&apos;ll implement a lighting system too, so the display will be quite colorful, but I want to keep the &quot;raw&quot; item colors in a pretty narrow range to keep things readable.</blockquote><p>I&apos;d forgotten that I wanted to implement a lighting system! I was thinking of an earlier antecedent of Adrift, an experiment that I did as Nintendo DS homebrew called <a href="https://github.com/nornagon/torch">Torch</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-4.png" class="kg-image" alt loading="lazy"><figcaption>Torch running on a DS emulator.</figcaption></figure><p>I&apos;m not sure if I want to go back to this&#x2014;I&apos;d been thinking that a more austere graphical approach might be appropriate to the theme&#x2014;but having recently been looking at Cogmind gifs again, I&apos;m definitely on the fence. Cogmind looks so good!</p><blockquote>The automatic doors (you know, like <em><em>Star Trek</em></em>) are now <a href="https://imgur.com/Bc2IP4k" rel="noopener nofollow ugc">broken up into two components</a>: a mounted presence sensor which detects nearby humans and emits an &quot;activate&quot; signal to items in the same tile, and the door itself, which can listen to the &quot;activate&quot; signal and open the door. If you take away the motion sensor (for instance, by dismantling it) then the door will be stuck. Eventually those mechanisms will also require power to work properly, and you&apos;ll also be able to hook up doors to other kinds of sensors and buttons.</blockquote><p>I think this is going to be an interesting and unique part of Adrift.</p><blockquote>I implemented a small message-based behavior system like the one <a href="https://www.youtube.com/watch?v=U03XXzcThGU" rel="noopener nofollow ugc">Brian Bucklew described</a> for Sproggiwood/Caves of Qud. I&apos;m not sure I quite like what I have yet, but I&apos;ll run with it and see how far I get.</blockquote><p>Still running with it. Still not sure I like it.</p><blockquote>I started on implementing a system for <a href="https://imgur.com/VOIn1rm" rel="noopener nofollow ugc">item damage</a>: sometimes, items have components that are broken, and you&apos;ll need to take them apart and fix them. But taking an item apart can also damage it if you&apos;re not careful or your tools are sub-par (for example, dismantling a computer display with a hammer is unlikely to leave any delicate components in-tact).</blockquote><p>The system I implemented for this was very simplistic, and since Adrift is ultimately intended to be a very repair-focused game, I think it&apos;ll end up being expanded a lot. For example, one idea Nato had in this area was that items like doors that make a sound when you activate them should make a different sound if they&apos;re broken&#x2014;and the sound should differ based on <em>how the item is broken</em>! For instance, if the motor in the door is broken, it might make an impotent &quot;whrrrr&quot;ing sound; if the motion sensor is broken it won&apos;t make any sound at all (since the door didn&apos;t activate); if a panel is bent it might make a &quot;clonk&quot; noise. I love this idea, though I think it would be too much work to apply it everywhere, doing it for some common items like doors would be well worth it.</p><blockquote>Items should have a mass and a volume, and you shouldn&apos;t be able to pick up things that are too big or too heavy. An item&apos;s mass should be simply the sum of the masses of its components (and eventually, once there are containers, its contents), but an item&apos;s volume could be bigger than the sum of the volumes of its components.</blockquote><p>Still haven&apos;t done this, but I still want to.</p><blockquote>I want to make a start on the power system. I&apos;m not quite sure how it should work yet, but I have thoughts about transformers and voltages and wires that you can drag across the floor to plug stuff into other stuff.</blockquote><p>I implemented a very simplistic power system, just enough to make it so that the ship can run out of power and doors stop opening.</p><h2 id="the-parts-have-parts">The Parts Have Parts</h2><p>Adrift is a roguelike without combat. Instead, Adrift <a href="https://www.reddit.com/r/roguelikedev/comments/9tpj5n/sharing_saturday_231/e8zasy5/">focuses very heavily on items</a>, furniture, and environmental elements, as well as the systems of the space ship that is its setting.</p><blockquote>I added support for non-rectangular rooms to the map generator, and to test it I added an <a href="https://imgur.com/j1c924G" rel="noopener nofollow ugc">air mix room</a> with a bunch of gas tanks. None of them do anything yet, but eventually all those tanks will be hooked up to the machines in the center, and the machines will be regulating the atmosphere on the ship.</blockquote><blockquote>Nato added an <a href="https://imgur.com/ehtM8vr" rel="noopener nofollow ugc">airlock room</a>, and I tweaked the map generation so they only spawn next to space. (Not much point having an airlock elsewhere, I suppose.) The structure of the ship is a spinning cylinder, so the map will wrap around in the X direction, but along the Y direction the ends will be the vacuum of space. I have some thoughts about movement in microgravity for when you travel inwards to the center of the cylinder...</blockquote><blockquote>Oh, and those spacesuits Nato added? They&apos;re <a href="https://imgur.com/o8VyFXu" rel="noopener nofollow ugc">full of parts</a>. And the parts have parts.</blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-5.png" class="kg-image" alt loading="lazy"><figcaption>Each of those parts has parts.</figcaption></figure><blockquote>I didn&apos;t make any headway on adding mass and volume to items yet, but I did start working on power a little. There&apos;s a soldering iron item that you can find (which you need to be able to disassemble stuff that&apos;s soldered together, like electronics), and I&apos;m in the process of making it so that the soldering iron has a battery which gets depleted when used, and the tool becomes useless once the battery is dead. As part of that I&apos;ve also had to make it possible for items be partially disassembled, because something has to happen if your soldering iron runs out halfway through taking apart a door.</blockquote><h2 id="cables">Cables</h2><p>If you have to repair a broken space ship, there&apos;s definitely going to be some <a href="https://www.reddit.com/r/roguelikedev/comments/9vppnn/sharing_saturday_232/e9gxhk8/">messing about with cables</a>.</p><blockquote>This week I&apos;ve been working towards implementing a ship-wide power system that things can plug into, but I found I needed a few other pieces first. In particular, there&apos;d be no point to a power system if you couldn&apos;t plug anything in, would there? So I added <a href="https://imgur.com/rbUa9h1" rel="noopener nofollow ugc">cables</a> that you can unspool and drag along the floor to plug things together. Right now, plugging things into each other does nothing, but in future you&apos;ll be able to connect up machines to each other using power cables. I have some thoughts about doing semi-realistic power transmission systems involving transformers and high-voltage / low-voltage lines, but that&apos;s for another day...</blockquote><blockquote>I&apos;ve also started thinking more about how to make the whole ship feel more <em><em>designed</em></em>. Right now there&apos;s just a random jumble of rooms without much logic or sense to it. I did some good brainstorming with Nato last weekend and came up with what I think is a pretty good 3-layer system for thinking about the map layout:<br><br>First, generate a &quot;schematic&quot; for the ship, which shows where the crew sector is, where engineering is, and so on.<br><br>Then, lay down &quot;superblocks&quot; that are groups of rooms that are restricted to be laid out in a certain way, without yet specifying exactly which rooms will be placed.<br><br>Lastly, place the individual rooms within the superblocks, completing the map.</blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-6.png" class="kg-image" alt loading="lazy"><figcaption>A sketch of the hierarchical layered approach to map generation.</figcaption></figure><p>I tried the &quot;superblock&quot; system out and I didn&apos;t like it. I think there&apos;s still potentially merit in the layered approach though; I&apos;ll probably resurrect it when I start thinking about placing rooms in specific places in the ship according to their type.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-7.png" class="kg-image" alt loading="lazy"><figcaption>One day this elevator will take you up to the ship&apos;s zero-gee spine.</figcaption></figure><h2 id="superblocks">Superblocks</h2><p>I was <a href="https://www.reddit.com/r/roguelikedev/comments/9xrmvz/sharing_saturday_233/ea0pjfa/">still keen</a> on this superblock thing.</p><blockquote>Last week I said I wanted to work on building out the ship power system and making the map generation feel more &apos;designed&apos;, and I&apos;ve done some of both of those things. On the map generation front, I&apos;ve built out the superblock system to the point where it&apos;s working, so now the map generator first lays out the schematic, then fills it in with superblocks, and <em><em>then</em></em> drops in the specific rooms. Here&apos;s the <a href="https://imgur.com/d5Uycqr" rel="noopener nofollow ugc">superblock layout</a> and the <a href="https://imgur.com/ydNEMqy" rel="noopener nofollow ugc">filled-in map</a> (both of these screenshots show <em><em>connections</em></em> between superblocks/rooms rather than the rooms themselves; each character in the filled-in map represents one 5x5 tile room in the final map).<br><br>On the power system side, the cables I made a couple of weeks ago do actually now function to pass power between things&#x2014;there are still a whole ton of bugs here, but it least it sort of works! You can disassemble a soldering iron, plug a power cable into the battery, then plug the other end of the cable into an automatic door to get it working again even when ship power is down. At least, until the battery runs out. Here&apos;s a <a href="https://youtu.be/ULPzmxheVaw" rel="noopener nofollow ugc">video of me jury-rigging a door</a>: it&apos;s stuck open at first, then I disassemble a soldering iron to get its battery, and plug the battery into the door, which returns to working condition (temporarily).</blockquote><blockquote>Finally, here you can see a rather poor quality animation of the map generation in action. You can see that in the lower area of the ship it has some trouble choosing what rooms to place and tries a few times before &quot;getting&quot; it and moving on to the top layer. All driven by <a href="https://github.com/chocoteam/choco-solver" rel="noopener nofollow ugc">choco</a> and <a href="https://github.com/chocoteam/choco-graph" rel="noopener nofollow ugc">choco-graph</a> :)</blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/adrift---map-generation.2020-05-23-18_54_34.gif" class="kg-image" alt loading="lazy"><figcaption>WFC-like map generation with superblocks. Each character is a room, and the characters are connected where there&apos;s a corridor or door connecting two adjacent rooms.</figcaption></figure><hr><p>I stopped posting updates on r/roguelikedev around the end of 2018, and also mostly stopped working on Adrift. I picked it back up in late 2019, and started working on it weekly with Nato&apos;s help. (Thanks Nato!)</p><p>Here&apos;s an abridged list of things we&apos;ve added since then:</p><ul><li>Atmosphere simulation. Each tile on the map has a gas composition, represented as partial pressure of various atmospheric gases (currently CO&#x2082;, O&#x2082; and N).</li><li>Plants. They grow, flower, are pollinated (by tiny flying robots), and bear fruit. Plants absorb CO&#x2082; and emit O&#x2082;. At some point they&apos;ll also interact with some growth medium, i.e. soil or water, as well as require light to grow.</li><li>Heat. The ship starts out very cold, and as you exchange heat with the environment, your core body temperature drops very quickly and you&apos;ll eventually die of hypothermia. Clothes can help you maintain homeostasis. We don&apos;t model metabolism yet so your body in the game is basically an RTG.</li><li>Cylindrical topology. The ship is constructed as a spinning cylinder, which you walk around on the inside of. So there&apos;s no left/right edge of the map, but there is a top/bottom.</li><li>WFC-like room layout generation. The rooms that the higher-level BSP algorithm generates have nonuniform shapes, which makes generating the contents of those rooms challenging. Adrift uses a constraint-based algorithm to assemble rooms of arbitrary shapes from &quot;puzzle pieces&quot;.</li></ul><p>We also experimented fairly extensively with the idea of using a genetic algorithm to generate levels. It didn&apos;t end up working out but we had fun and read <a href="http://nn.cs.utexas.edu/downloads/papers/stanley.ec02.pdf">some</a> <a href="https://www.joelsimon.net/evo_floorplans.html">cool</a> <a href="http://www.graphviz.org/Documentation/GKN04.pdf">papers</a>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-8.png" class="kg-image" alt loading="lazy"><figcaption>Debug image for a GA-based room layout algorithm.</figcaption></figure><p>Nato also has some really cool ideas for how electronics might work:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/image-9.png" class="kg-image" alt loading="lazy"><figcaption>This sort of board might be hooked up to a sensor system that controls a life support module, or opens a door, or controls a bulkhead door that&apos;s part of a fire suppression system, or...</figcaption></figure><hr><p>I really want to get Adrift to the point where it&apos;s playable for someone who isn&apos;t me, to the point where it&apos;s at least barely, just a little, getting across some of what I have in mind for the game.</p><p>There are three main parts of the game arc that I think are necessary to show the scope of what I have in mind.</p><ol><li><strong>&quot;Cold &amp; afraid&quot;</strong> - you&apos;re decanted from your cryopod, and you&apos;re naked, starving, and freezing cold. You have to find food and clothes, fast, or you&apos;re going to die.<br><strong>Mechanics needed:</strong> hunger, thirst, eating/drinking, death by starvation/thirst, death by temperature excursion. I think it&apos;s OK in the first alpha for it to be relatively easy to get out of the cryopod room and find food/clothes, it just has to be the case that you&apos;ll die if you don&apos;t.<br><strong>Content needed:</strong> preserved food, clothing, more room variety in crew quarters.</li><li><strong>&quot;Survive &amp; thrive&quot;</strong> - you&apos;ve found some warm clothes and a stash of freeze-dried fruit. That&apos;s enough to live, for now, but unless you get the hydroponics room online, you&apos;re going to find yourself at the end of your supplies in short order. Also, is it just you, or is the ship getting colder?<br><strong>Mechanics needed:</strong> plant growing needs to be balanced &amp; fleshed out (e.g. dirt, light, water requirements), dangers/damage that prevent you from exploring the entire ship, crafting/disassembly, life support system (incl. pipes/wires?), repairable damage to ship systems.<br><strong>Content needed:</strong> life support rooms, item damage design, food preservation machines / methods, variety in rooms in engineering.</li><li><strong>&quot;What happened?&quot;</strong> - this is the end-game, and involves finding your way to the bridge.<br><strong>Mechanics needed:</strong> high-level map topology (i.e. cylindrical shape of main deck, multiple levels), functioning elevators.<br><strong>Content needed:</strong> backstory/lore hints, bridge rooms, mid-deck rooms.</li></ol><p>That&apos;s all for now. I&apos;ll close with some inspiration.</p><figure class="kg-card kg-embed-card"><iframe width="480" height="270" src="https://www.youtube.com/embed/DhmdyQdu96M?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure>]]></content:encoded></item><item><title><![CDATA[Adrift map generation: binary space partitioning]]></title><description><![CDATA[<p>I&apos;ve been working on map generation in Adrift this week. I&apos;ve been through a few different unsatisfying iterations of the map generation code and I&apos;m finally feeling like I&apos;ve encountered a rich algorithmic vein, so I wanted to write a little bit</p>]]></description><link>https://blog.nornagon.net/adrift-map-generation-binary-space-partitioning/</link><guid isPermaLink="false">5ec9a56fee24ec00014203da</guid><category><![CDATA[Adrift]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sat, 23 May 2020 23:38:06 GMT</pubDate><media:content url="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-23-at-4.51.38-PM.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.nornagon.net/content/images/2020/05/Screen-Shot-2020-05-23-at-4.51.38-PM.png" alt="Adrift map generation: binary space partitioning"><p>I&apos;ve been working on map generation in Adrift this week. I&apos;ve been through a few different unsatisfying iterations of the map generation code and I&apos;m finally feeling like I&apos;ve encountered a rich algorithmic vein, so I wanted to write a little bit about what&apos;s been working.</p><p>The world of Adrift is a space ship, so unlike a lot of other roguelike environments, I want it to feel <em>designed</em>. There are a lot of examples of map generation algorithms for generating caves, or dungeons, where a little chaos is acceptable (or even desirable). But not so many examples of algorithms which try to generate something that feels ordered. Another challenge is that if we&apos;re generating a space ship, we want to fill all the available space&#x2014;anything less would be wasteful!</p><p>I spent a long time trying to make use of the idea of symmetry, to try to generate maps that were symmetrical and thereby create a feeling of orderedness. I never found anything that felt like it hit the right balance between randomness and orderedness. But a few weeks ago, my collaborator Nato said something that made my brain click into a new place. He said that it&apos;s a generation ship&#x2014;it&apos;s more like a city than a spaceship. And that got me thinking about city grids, like this block in Chicago.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/chicago___OpenStreetMap.png" class="kg-image" alt="Adrift map generation: binary space partitioning" loading="lazy"><figcaption>A group of blocks in downtown Chicago, near the university.</figcaption></figure><p>If this were generated output, I think it hits a really good place on the ordered/chaotic spectrum! It has a lot of parallel lines, and blocks of similar sizes, but it&apos;s broken up so that it doesn&apos;t seem mathematical. It feels lived-in. That&apos;s what I want to capture!</p><p>I immediately thought of binary space partitioning as a way to produce this sort of layout. There&apos;s a pretty good description of BSP <a href="https://www.youtube.com/watch?v=W_E93kXmHVc">here</a> (as video), or if you happen to have a copy of <a href="https://www.indiebound.org/book/9781498799195">Procedural Generation in Game Design</a>, there&apos;s a great chapter in there by Brian Bucklew on space partitioning of various kinds, including binary. I&apos;d recommend either or both of those if you want to implement this yourself. At a high level, the process is this:</p><ol><li>Start with a rectangle.</li><li>Cut it in two. You now have two rectangles.</li><li>Recurse.</li></ol><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/05/Adrift-1.png" class="kg-image" alt="Adrift map generation: binary space partitioning" loading="lazy"><figcaption>The BSP algorithm creates a bunch of irregularly-shaped rectangles. There&apos;s a little extra logic in here to make room for the corridors.</figcaption></figure><p>There&apos;s still a bit more tweaking that I want to do to get things working right. For starters, there are a lot of long thin rooms in that example that I think I can eliminate, either by merging them into adjacent rooms, or by setting a minimum size when splitting larger rectangles. Currently, the algorithm terminates when a room gets below a certain cut-off area threshold, which means most rooms are about the same size, but I&apos;d like some rooms to be larger to accommodate some more variation in the space, and to make room for larger areas like arboreta, recycling plants, engine rooms and so on. But I think this algorithm has legs! It&apos;s flexible, it&apos;s simple, and it generates layouts that I like.</p><p>Here&apos;s how it looks in the game (with FOV turned off so you can see the layout):</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://blog.nornagon.net/content/images/2020/05/image.png" class="kg-image" alt="Adrift map generation: binary space partitioning" loading="lazy"></figure><p>Next time: how to fill rooms with room-type-appropriate furniture when they&apos;re not a fixed shape!</p>]]></content:encoded></item><item><title><![CDATA[Soul food]]></title><description><![CDATA[There's a lot in this verse. I think Laozi is wrestling with the nature of the world—there are bad things, ugly things, hard things. Why? Because without them, there would be no good things, beautiful things, easy things.]]></description><link>https://blog.nornagon.net/soul-food/</link><guid isPermaLink="false">5e95f038162871000117bb70</guid><category><![CDATA[Tao]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Fri, 22 May 2020 15:14:36 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><div class="cols">
    <div><!--kg-card-end: html--><blockquote>Everybody on earth knowing<br>that beauty is beautiful<br>makes ugliness.<br><br>Everybody knowing<br>that goodness is good<br>makes wickedness.<br><br>For being and nonbeing<br>arise together;<br>hard and easy<br>complete each other;<br>long and short<br>shape each other;<br>high and low<br>depend on each other;<br>note and voice<br>make the music together;<br>before and after<br>follow each other.<br><br>That&#x2019;s why the wise soul<br>does without doing,<br>teaches without talking.<br><br>The things of this world<br>exist, they are;<br>you can&#x2019;t refuse them.<br><br>To bear and not to own;<br>to act and not lay claim;<br>to do the work and let it go:<br>for just letting it go<br>is what makes it stay.</blockquote><p>&#x2014;Ursula K. Le Guin</p><!--kg-card-begin: html--></div><div><!--kg-card-end: html--><blockquote>When people see some things as beautiful,<br>other things become ugly.<br>When people see some things as good,<br>other things become bad.<br><br>Being and non-being create each other.<br>Difficult and easy support each other.<br>Long and short define each other.<br>High and low depend on each other.<br>Before and after follow each other.<br><br>Therefore the Master<br>acts without doing anything<br>and teaches without saying anything.<br>Things arise and she lets them come;<br>things disappear and she lets them go.<br>She has but doesn&apos;t possess,<br>acts but doesn&apos;t expect.<br>When her work is done, she forgets it.<br>That is why it lasts forever. </blockquote><p>&#x2014;Stephen Mitchell</p><!--kg-card-begin: html--></div><div><!--kg-card-end: html--><blockquote>If something is beautiful, something else must be ugly.<br>If something is good, something else must be bad.<br><br>You can&apos;t have something without nothing.<br>If no task is difficult,<br>then no task is easy.<br>Things are up high<br>because other things are down low.<br>You know when you&apos;re listening to music<br>because you don&apos;t hear noise.<br>And something else came first, so this must be next.<br><br>The Masters get the job done without moving a muscle<br>and signify without saying a word.<br>When things around them fall apart, they stay cool.<br>They don&apos;t own much,<br>but they use whatever&apos;s at hand.<br>They do the work without expecting any favors.<br>When the job is finished,<br>they move on to the next job.<br>That&apos;s why their work is so damn good.</blockquote><p>&#x2014;Ron Hogan</p><!--kg-card-begin: html--></div></div><!--kg-card-end: html--><p>There&apos;s a lot in this verse. I think Laozi is wrestling with the nature of the world&#x2014;there are bad things, ugly things, hard things. Why? Because without them, there would be no good things, beautiful things, easy things.</p><p>How is one supposed to move and behave in this world full of death and hatred and meanness and awful things? Well, refusing to acknowledge that things are that way is not an option. Laozi says: let go of your expectations. Don&apos;t hold on to stuff. Not the good stuff or the bad stuff.</p><p>&#x627;&#x6CC;&#x646; &#x646;&#x6CC;&#x632; &#x628;&#x6AF;&#x630;&#x631;&#x62F;&#x200E;, <em>this too shall pass.</em></p>]]></content:encoded></item><item><title><![CDATA[Taoing]]></title><description><![CDATA[I first encountered the Tao Te Ching when I was 22 years old. I don't remember how I came across it. Maybe I'd heard that it was a book of wisdom, and decided I could use some of that.]]></description><link>https://blog.nornagon.net/taoing/</link><guid isPermaLink="false">5e94e50f162871000117b9c0</guid><category><![CDATA[Tao]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Tue, 14 Apr 2020 04:11:18 GMT</pubDate><content:encoded><![CDATA[<!--kg-card-begin: html--><div class="cols">
    <div><!--kg-card-end: html--><blockquote>The way you can go<br>isn&#x2019;t the real way.<br>The name you can say<br>isn&#x2019;t the real name.<br><br>Heaven and earth<br>begin in the unnamed:<br>name&#x2019;s the mother<br>of the ten thousand things.<br><br>So the unwanting soul<br>sees what&#x2019;s hidden,<br>and the ever-wanting soul<br>sees only what it wants.<br><br>Two things, one origin,<br>but different in name,<br>whose identity is mystery.<br>Mystery of all mysteries!<br>The door to the hidden.</blockquote><p>&#x2014;Ursula K. Le Guin</p><!--kg-card-begin: html--></div><div><!--kg-card-end: html--><blockquote>The tao that can be told<br>is not the eternal Tao<br>The name that can be named<br>is not the eternal Name.<br><br>The unnamable is the eternally real.<br>Naming is the origin<br>of all particular things.<br><br>Free from desire, you realize the mystery.<br>Caught in desire, you see only the manifestations.<br><br>Yet mystery and manifestations<br>arise from the same source.<br>This source is called darkness.<br><br>Darkness within darkness.<br>The gateway to all understanding.</blockquote><p>&#x2014;Stephen Mitchell</p><!--kg-card-begin: html--></div><div><!--kg-card-end: html--><blockquote>If you can talk about it,<br>it ain&apos;t Tao.<br>If it has a name,<br>it&apos;s just another thing.<br><br>Tao doesn&apos;t have a name.<br>Names are for ordinary things.<br><br>Stop wanting stuff. It keeps you from seeing what&apos;s real.<br>When you want stuff, all you see are things.<br><br>These two statements have the same meaning.<br>Figure them out, and you&apos;ve got it made.</blockquote><p>&#x2014;Ron Hogan</p><!--kg-card-begin: html--></div></div><!--kg-card-end: html--><p>I first encountered the Tao Te Ching when I was 22 years old. I don&apos;t remember how I came across it. Maybe I&apos;d heard that it was a book of wisdom, and decided I could use some of that.</p><p>It&apos;s not the sort of book that tends to leave one&apos;s mind easily, once it enters. It has a timeless quality to it, seemingly as relevant today as it must have been over two millennia ago when it was penned (brushed?). Recently, thinking about <a href="https://blog.nornagon.net/eudaimonia/">creativity</a>, the Tao bubbled to the top of my mind again, and I cracked open one of my favourite translations of it, by the inimitable Ursula K. Le Guin.</p><p>Mostly as a way to trick myself into spending more time with this beautiful text, I thought it would be a good idea to read through a few different translations and write a little about what meaning I&apos;m finding in each chapter. I&apos;m far from a scholar of the Tao Te Ching, and I know nothing whatsoever about religious Taoism. But Laozi teaches, <em>fill the bowl to the brim and it will spill</em>. So, perhaps, my bowl is half-full. No chance of a spill!</p><p>The three translations I&apos;ve chosen are Le Guin&apos;s (which is by her admission more of an interpretation than a translation), that of Stephen Mitchell (which is trying to be more faithful to the original, though is still fairly modern), and Ron Hogan&apos;s (which attempts as far as possible to extricate the text from the &apos;wisdom of the ancients&apos; feeling that other translations ooze). Hogan&apos;s was the version that spoke to me the loudest when I was 22. It seems a little hokey to me now, and I prefer Le Guin&apos;s version. But I still think there&apos;s something lovely about Hogan&apos;s friendliness and straightforwardness.</p><hr><p>So, the opening verse of the Tao Te Ching. Le Guin calls it &quot;Taoing&quot; and writes that to her, it encapsulates the entirety of the rest of the work. Perhaps I&apos;m insufficiently enlightened, but I don&apos;t see it, at least not today.</p><p>The idea that if I can talk about it, and name it, then it isn&apos;t Tao, bothers me. Isn&apos;t that a bit of an evasion? A way to say, &quot;ah, sorry, I can&apos;t just <em>tell</em> you the secret&quot;? Though at the same time it seems obviously, self-evidently true. If it could be spoken, simply told to you, then life would be a solved problem. It&apos;s also sort of a warning against taking advice&#x2014;&quot;if someone tells you how to live, then they&apos;re definitely wrong&quot;, which just about captures how I feel about books like 7 Habits and Getting Things Done. Pretty self-deprecating, for a book that&apos;s sometimes thought of as containing the meaning of life.</p><p>I have to be honest, I don&apos;t really understand the bit about names being the origin of everything. Hogan dodges that bit, even. My best guess here is maybe this is about defining the self. It&apos;s pointing out that naming things, and thus dividing the world, is a personal thing that happens in your mind, not a property of the world itself. Like <a href="https://acim.org/workbook/lesson-51/">Lesson 51</a> (you may prefer <a href="https://open.spotify.com/track/4mK9JYoOt7SqmqWUI93JBl?si=Klz3TP2YQ1GT-ASe9-4NNA">Pilote&apos;s version</a>), &quot;I have given what I see all the meaning it has for me&quot;.</p><p>(Side note: ACIM&apos;s Lesson 51 has a lot of Tao in it, like &quot;I am willing to recognize the lack of validity in my judgments, because I want to see&quot; vs the TTC&apos;s &quot;Can you step back from your own mind and thus understand all things?&quot; in chapter 10. I have no idea what ACIM is, but their website is killer.)</p><p>The third bit&#x2014;about the unwanting and the ever-wanting&#x2014;gives me strong echoes of a feeling I wrote about last week. I wrote about wanting to create things, about wanting to create things I&apos;m proud of. I want that a lot. The Tao is telling me, here, that the wanting is showing me lack. It&apos;s showing me what I don&apos;t have. And offering that, maybe, to unwant would be to see past that and connect to something truer. Or would that just be a salve to make me comfortable with my current status quo? I don&apos;t know. A lot of the Tao Te Ching is about <em>wei wu wei</em>, doing not doing, acting by inaction. I wonder sometimes about whether that is implicitly supporting the way things are, encouraging complacency.</p><p>But what would I know? My bowl is only half full.</p>]]></content:encoded></item><item><title><![CDATA[Eudaimonia]]></title><description><![CDATA[<p>I think of myself as a creative person, in that I find pleasure in creating, and I&apos;m drawn to the act of creation. I want to bring into the world things that weren&apos;t already there. I know that to be true about myself, but <em>why</em> it&</p>]]></description><link>https://blog.nornagon.net/eudaimonia/</link><guid isPermaLink="false">5e815c085f3dde000109a64c</guid><category><![CDATA[Creativity]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sun, 05 Apr 2020 22:55:05 GMT</pubDate><content:encoded><![CDATA[<p>I think of myself as a creative person, in that I find pleasure in creating, and I&apos;m drawn to the act of creation. I want to bring into the world things that weren&apos;t already there. I know that to be true about myself, but <em>why</em> it&apos;s true is elusive to me (I suppose search for meaning is always elusive). Is my need to create an irreducible personal truth? Or is it in service of some other need?&#x2014;perhaps, a need to be understood, or to be known?</p><p>I haven&apos;t found a great deal of satisfaction in my creative life. I start a lot of things and rarely finish them. I distract myself with incidental complexity, or other projects, or rewriting in Rust, and lose sight of whatever creative vision I began with. It&apos;s familiar for me to feel torn between a lot of projects, to feel paralyzed by the idea that if I was to work on any one of them I&apos;d be neglecting all the others&#x2014;which usually ends up with me working on none of them. I&apos;m afraid of falling short of my own expectations. And hey, if I never finish a thing, it can&apos;t be a disappointment, right?</p><p>I want to work on that. On feeling more satisfied. I don&apos;t have any great answers, though: I&apos;m struggling with it, trying to figure out what feels good to me, what blocks me, and how to be gentle with myself when what I make is disappointing to me. But I know that I don&apos;t want to stay this dissatisfied.</p><p>So what would it look like to be more satisfied with my creative work? And how would I take a step along the path to finding that satisfaction? Ira Glass says you just have to <a href="https://www.brainpickings.org/2014/01/29/ira-glass-success-daniel-sax/">make a lot of crap</a>. I hate making crap. I think I need some coping strategies.</p><p>When I think about the things I&apos;ve made that I feel satisfied with, the things I&apos;m proud of having made, I&apos;ve noticed that it&apos;s the things that I&apos;ve shown to people. Especially, it&apos;s the things I&apos;ve made which others have found useful or interesting that I find most satisfying. I feel satisfied with <a href="https://github.com/nornagon/saxi">saxi</a>, <a href="https://github.com/ottypes/json0">json0</a>, and <a href="https://github.com/nornagon/hf-mission-planner">hf-mission-planner</a>. I&apos;m proud of having <a href="https://www.instagram.com/p/B4ShaEAhfOz/">completed Inktober</a> in 2019. In my mind those projects are at peace. When I think of them, I feel happy with where they are, even if they&apos;re not perfect, or not &quot;finished&quot;. By contrast, the far greater quantity of my unfinished and unreleased projects, the things I haven&apos;t shown to people, feels oppressive and restless. Those unfinished things haunt me and cry out for my attention, and I have to say to it all, over and over, sorry, today I&apos;m not interested enough to work on you.</p><p>So maybe I could find more satisfaction by focusing on showing more work, on talking to people about the things I&apos;m making. Although perhaps there&apos;s a correlation&#x2013;causation confusion, and it&apos;s the case that being satisfied with something causes me to show it off, or that some things I make are good, and I&apos;m both satisfied with the good things and choose to show them off. Or perhaps the feeling of satisfaction is primal, and the work incidental: rather than seeking to make things with which I&apos;m more satisfied, I should cultivate a general feeling of satisfaction, and only then will I be able to make things that satisfy me.</p><p>In any case, I don&apos;t feel that my dissatisfaction is serving me well, and so I want to reduce it. Maybe talking and writing about things I&apos;m making will help me with that. It&apos;s worth a shot, anyway.</p><p></p><p>Also, I should probably set fire to that pile of old projects. They&apos;re not serving me either.</p><hr><p>I&apos;ve written about creativity before: about <a href="https://blog.nornagon.net/intentionally-imperfect/">shunning the empty promise of perfection</a>, the <a href="https://blog.nornagon.net/the-doldrums/">doldrums</a> and the <a href="https://blog.nornagon.net/the-wind/">wind</a>, and about <a href="https://blog.nornagon.net/incremental-progress/">taking pleasure in making small steps</a>.</p>]]></content:encoded></item><item><title><![CDATA[Cybots]]></title><description><![CDATA[<p>There&apos;s a browser game I used to play at high school (discreetly, or at least so I thought) called Cybots, of which nearly all trace appears to have disappeared. All that remains is a <a href="https://www.facebook.com/Cybots">lonely Facebook page</a>, an adorable <a href="http://cybots.pbworks.com/w/page/36426015/Newbie%20strategy%20guide">bitrotting PBWiki</a>, and this ballin&apos; <a href="http://www.geocities.ws/clan_dragon_fire_home/cybotfaq.html">GeoCities clan page</a></p>]]></description><link>https://blog.nornagon.net/cybots/</link><guid isPermaLink="false">5e1d5d248a940e0001bc12ed</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Tue, 21 Jan 2020 05:23:59 GMT</pubDate><content:encoded><![CDATA[<p>There&apos;s a browser game I used to play at high school (discreetly, or at least so I thought) called Cybots, of which nearly all trace appears to have disappeared. All that remains is a <a href="https://www.facebook.com/Cybots">lonely Facebook page</a>, an adorable <a href="http://cybots.pbworks.com/w/page/36426015/Newbie%20strategy%20guide">bitrotting PBWiki</a>, and this ballin&apos; <a href="http://www.geocities.ws/clan_dragon_fire_home/cybotfaq.html">GeoCities clan page</a>. I miss it.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/01/image.png" class="kg-image" alt loading="lazy"><figcaption>awww yeah i can feel the &apos;90s</figcaption></figure><blockquote>Uh, wait. While I was writing this article, I discovered that the fellow who created the game, Martin Wells, is a friend of a friend of mine. I sent him a connection request on LinkedIn and mentioned Cybots, and we chatted for a bit and he brought the game back up! You can try it out at <a href="http://playcybots.com">playcybots.com</a> if you&apos;re so inclined. Also, the tech world is so damn small. Also, definitely the best thing that LinkedIn has ever done for me.</blockquote><p>So hat do I miss about it? What was Cybots? <s>Sadly I can&apos;t find any screenshots to share</s>, but it was a browser game in a similar vein to <a href="https://www.kingdomofloathing.com/">Kingdom of Loathing</a>. You were the controller of a squad of violent robots patrolling the Vulcore Plains, hiring mercenaries, escorting tag droids, and generally causing (or running away from) mayhem. As you, er, liberated credits from your enemies, you could buy better stuff for your squad to increase the ratio of mayhem caused to mayhem fled from. I&apos;ll admit that Cybots was not a paragon of game design and probably 80% of what I miss about it is down to nostalgia. But I think it did some things pretty well.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/01/Cybots-combat.png" class="kg-image" alt loading="lazy" width="2000" height="1534" srcset="https://blog.nornagon.net/content/images/size/w600/2020/01/Cybots-combat.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/01/Cybots-combat.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2020/01/Cybots-combat.png 1600w, https://blog.nornagon.net/content/images/2020/01/Cybots-combat.png 2318w" sizes="(min-width: 1200px) 1200px"><figcaption>My two Ranger bots, Kelly and Aragorn, face off against an enemy in the Vulcore Plains.</figcaption></figure><p>One mechanic I really liked in Cybots and still find myself drawn to is that each action you took cost &quot;KCharge&quot;, and KCharge replenished in real time. That is, there was a limit to the amount you could play each day. A lot of other games do this now (e.g. <a href="https://fallenlondon.com">Fallen London</a>, and lots of f2p mobile games), usually with the option to buy more credits with real world money. But I think limiting the number of actions per day can be an interesting design choice even leaving aside its potential for extracting dollars from players.</p><p>Limiting actions guides players away from exploring the game by &quot;spamming&quot;, and towards a careful consideration of how they spend their time with the game, drawing the player into the mechanics more than they might have been otherwise, or into the non-action-using bits of the game (e.g. lore or art). It respects the player&apos;s time by giving them a cue to stop playing (though it might counteract this somewhat by being a bit of a psychological trick to draw the player back to the game the next day).</p><p>Another nice consequence of limiting the number of actions each player can take per day is that it levels the playing field in terms of what every player has access to. There isn&apos;t really anything meaningful you can do in Cybots without KCharge&#x2014;you can mess about with the equipment on your squad, but that&apos;s about it&#x2014;and everyone gets the same amount of it. It&apos;s pretty easy to use up all your KC for the day in under an hour, which is a fairly low amount of time to spend on a game each day. So it stops the players who have the most time on their hands from being the winners every time.</p><p>The early 2000s was a different time in terms of Internet culture, and the chat frame that Cybots included at the bottom of the game was not the pit of vile adolescent swill we&apos;ve come to expect from online multiplayer games. I really enjoyed chatting to other players who were online at the same time as me, though I&apos;m not sure the same feature would work well for games being developed today. Look no further than <a href="https://wowwiki.fandom.com/wiki/Barrens_chat">Barrens chat</a> for an example of why.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/2020/01/Cybots---Azra-s-Arena.png" class="kg-image" alt loading="lazy" width="2000" height="1534" srcset="https://blog.nornagon.net/content/images/size/w600/2020/01/Cybots---Azra-s-Arena.png 600w, https://blog.nornagon.net/content/images/size/w1000/2020/01/Cybots---Azra-s-Arena.png 1000w, https://blog.nornagon.net/content/images/size/w1600/2020/01/Cybots---Azra-s-Arena.png 1600w, https://blog.nornagon.net/content/images/2020/01/Cybots---Azra-s-Arena.png 2318w" sizes="(min-width: 1200px) 1200px"><figcaption>Azra&apos;s arena, in the lava fields, where you go to farm cash.</figcaption></figure><hr><p>I have an itch to make a clone/homage to Cybots one day, perhaps changing up the theme and combat mechanics but keeping the same structure: a squad of characters whom you equip with various items, intermittent battles interspersed with exploring a semi-random set of areas described with text. Reading about storylets and narrative delivery systems in <a href="https://mkremins.github.io/publications/Storylets_SketchingAMap.pdf">this paper by Max Kreminski</a> (<em>Sketching a Map of the Storylets Design Space</em>) lead me to the realization that, combat aside, the structure of Cybots is very similar to the structure of <a href="http://reignsgame.com/reigns/">Reigns</a>: there&apos;s a &quot;deck&quot; of cards which you draw randomly from. What cards are available to you in the deck at any given time depends on the state of your character (and possibly other global state). But you only get to see one at a time. You can also &quot;travel&quot; to different areas&#x2014;in Reigns, the dungeon would be an example, or in Cybots, the Vulcore Plateau&#x2014;which changes the available set of cards.</p><p>I&apos;ll throw it on the pile of &quot;one day&quot; projects, I suppose. It would make a good jam game!</p>]]></content:encoded></item><item><title><![CDATA[Are more people eating plant-based diets?]]></title><description><![CDATA[
Earlier this year, I read Drawdown, a survey of tools and techniques for addressing climate change ranked by impact. It’s an exceptionally…
]]></description><link>https://blog.nornagon.net/are-more-people-eating-plant-based-diets-/</link><guid isPermaLink="false">5e81657b162871000117b663</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Mon, 17 Sep 2018 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p>Earlier this year, I read <a href="https://www.drawdown.org/"><em>Drawdown</em></a>, a survey of tools and techniques for addressing climate change ranked by impact. It&#x2019;s an exceptionally well-researched book and you should read it, but what I want to talk about today is the part of the book that had the most impact on me personally.</p><p>The first thing that usually comes to mind when you think about solutions to climate change is renewable energy. But nearly half of the top 20 solutions that <em>Drawdown</em> identifies are related to food, and taken together, changes to the way we produce and eat food account for an impact more than 30% larger than changes to the way we generate electricity.</p><p>In particular, <em>Drawdown </em>estimates that the impact of <a href="https://www.drawdown.org/solutions/food/plant-rich-diet">shifting to a diet rich in plants</a> is the 4th-highest-impact of all the 100 solutions they examined, and projects that reducing meat consumption could result in a total reduction in CO&#x2082;-equivalent emissions of over 65,000,000,000 tons over the years from 2020&#x2013;2050. To put that in perspective, that&#x2019;s comparable to what <em>Drawdown</em> estimates will be the impact of shifting to solar power. It&#x2019;s six times the estimated impact of shifting to electric vehicles. And it would account for about as much less carbon in the atmosphere as does the ocean, which sequesters about 2.5 Gt/y [<a href="https://www.earth-syst-sci-data-discuss.net/5/1107/2012/essdd-5-1107-2012.pdf">1</a>]. <em>The ocean</em>. All of it.</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-F2cdTdFEUGbvGdg-8vb6Kg.jpeg" class="kg-image" alt loading="lazy"></figure><p>Since I read <em>Drawdown</em>, I&#x2019;ve been paying much closer attention to the amount of animal products that I eat. I don&#x2019;t eat zero meat, but I&#x2019;ve substantially reduced the amount of meat I eat, now at about one meal per week. And I&#x2019;m wondering if other people are doing the same.</p><p>I know that the Baader-Meinhof effect will mean I&#x2019;m more aware of stores and restaurants offering plant-based options, so it will seem to me subjectively that there&#x2019;s a growing movement of plant-based food even if there isn&#x2019;t. Data on vegetarianism and veganism is surprisingly difficult to pin down&#x2014;studies report anything from 4% to 13% of Americans are vegan or vegetarian[<a href="https://www.npr.org/sections/13.7/2017/06/28/532880755/is-a-no-meat-world-really-better">2</a>]&#x2014;and it&#x2019;s even harder to find data on people like me who aren&#x2019;t vegetarian <em>per se</em>, but are choosing to eat less meat. Things get even trickier when you try to correlate those numbers between countries.</p><p>Google Trends is far from an authoritative data source, but perhaps it can be a proxy as part of a broader investigation into whether plant-rich diets are on the rise. I looked at trends for searches for veganism, reasoning that I usually search for those things when I&#x2019;m eating out in a place I&#x2019;m unfamiliar with, and that it probably correlates with the number of people who are doing the same sort of thing.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-dpO2zhDTiPkQCyjytXHE_w.png" class="kg-image" alt loading="lazy"><figcaption>.</figcaption></figure><p>It&#x2019;s a little difficult to parse this chart, but it looks roughly like veganism is about twice as popular in the U.S. now as it was in 2013. And the trend holds up for other geographies than the U.S., too.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-O0cUmkfANJr2Ou-n0Yy9Iw.png" class="kg-image" alt loading="lazy"><figcaption>Japan</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-h8Sdns_K2EMxv0TqJllfgw.png" class="kg-image" alt loading="lazy"><figcaption>Australia</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-lxSYFLhmC2tRcR2M9a_Tqw.png" class="kg-image" alt loading="lazy"><figcaption>Worldwide</figcaption></figure><p>Google Trends only reports data about people who use Google, which notably excludes China (<a href="https://theintercept.com/2018/08/01/google-china-search-engine-censorship/">for now</a>) and, largely, India. That&#x2019;s more than 2 billion people in the world missing from this analysis. China has a rapidly growing middle class who often associate meat with wealth and status. India also has a rapidly growing middle class, but has a large number of adherents to Dharmic religions such as Jainism, Buddhism and Hinduism which prohibit the consumption of meat and as such, India is about 30% vegetarian already.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/0-rZsAq03TXtdudfUT.png" class="kg-image" alt loading="lazy"><figcaption>Vegetarian and non-vegetarian marks, required labelling for packaged foods in&#xA0;India.</figcaption></figure><p>These graphs would suggest that plant-based diets are on the rise in Western countries, and rapidly so&#x2014;2x in 5 years is an incredible rate of growth.</p><hr><p>Let&#x2019;s consult another source of data to see if these trends correlate! I grabbed the OECD&#x2019;s data on <a href="https://data.oecd.org/agroutput/meat-consumption.htm">meat consumption</a>, which includes kilograms-per-capita data for 43 countries going back to 1990. The built-in graphing function on the OECD website wouldn&#x2019;t show me summed meat consumption across types of meat (poultry, beef, etc.) so I downloaded the raw data and plotted it myself. The data for beef didn&#x2019;t go back before 2000 for some countries, so I&#x2019;ve plotted just the years 2000&#x2013;2017.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/1-R7K-WlHZS9ai0wBpDqNdhw.png" class="kg-image" alt loading="lazy"><figcaption> (2018), Meat consumption (indicator). doi: 10.1787/fa290fd0-en (Accessed on 16 September 2018).</figcaption></figure><p>This chart tells another story. While it looks like people in Europe and the U.S. are eating about the same amount of meat as they always have, people living in Brazil, Russia, India, China and South Africa (BRICS) are eating nearly 30% more meat than they did 20 years ago (though interestingly, meat consumption in India remains low). Worldwide, per-capita meat consumption is up 15% since 2000.</p><p>So it seems that while enthusiasm for plant-based diets is growing in the West (who are by far the hungriest for meat), it isn&#x2019;t yet an entrant into the cultures of the Global South (which contains vastly more people). Even though the average person in China consumes half as much meat as the average person in the U.S., there are four times as many people living in China.</p><p>I don&#x2019;t know what it will look like for plant-rich diets to take off in China, or Brazil, but it probably won&#x2019;t look like veganism in the West.</p><hr><p>Climate change isn&#x2019;t a problem that any one of us can have a significant impact on in our personal lives. The scale of the problem is such that effective actions are those at the scale of thousands to millions of people. But eating a plant-rich diet is by far the most impactful change you can make yourself, way way more than recycling or changing your lightbulbs. And you&#x2019;ll be living your values every time you eat a meal. Assuming you value the continued existence of human life on Earth, that is.</p><p>You don&#x2019;t have to eat 100% vegan&#x2014;as my wife Cole says, if everyone ate vegan half the time, it&#x2019;d be like half of us were vegan!&#x2014;but you do have to start now. We&#x2019;re running out of time.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Are-more-people-eating-plant-based-diets-/0-psn361a9C7ztm5TQ.jpg" class="kg-image" alt loading="lazy"><figcaption> and will make you more attractive. Guaranteed.</figcaption></figure>]]></content:encoded></item><item><title><![CDATA[Math for Game Developers: Parameterised Easing]]></title><description><![CDATA[
Or, How The Crap Do I Make That Curve?!
]]></description><link>https://blog.nornagon.net/math-for-game-developers--parameterised-easing/</link><guid isPermaLink="false">5e81657b162871000117b677</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Mon, 12 Mar 2018 00:00:00 GMT</pubDate><media:content url="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-I2RbDZNojEOYc8mw7qiMyg.png" medium="image"/><content:encoded><![CDATA[<h3 id="or-how-the-crap-do-i-make-that-curve-">Or, How The Crap Do I Make That&#xA0;Curve?!</h3><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-I2RbDZNojEOYc8mw7qiMyg.png" alt="Math for Game Developers: Parameterised Easing"><p>Sometimes I get an idea in my head that requires a particular kind of mathematical function: say, a cosine, or a logarithm, or a polynomial. Since I don&#x2019;t have much of a background in mathematics, it&#x2019;s more likely that I know the <em>shape</em> of function I want, but not how to write it down.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-VLY2HI7sxZS6Z4l-lakQqQ.jpeg" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>How do I get the computer to make this&#xA0;curve?</figcaption></figure><p>If I&#x2019;m lucky, some dusty corner of my mind will shake off the cobwebs that have been accumulating there since first year algebra and offer itself in service, saying something useful like &#x201C;Uh&#x2026; maybe try tanh?&#x201D;</p><p>But today I was unlucky. I wanted something kind of like a square wave, but not as harsh. A sine wave was too smooth, and a square wave was not smooth enough. Surely there must be some mathematical incantation I can utter that will solve this problem! I had the idea that I wanted to start with a sine wave and &#x201C;squash&#x201D; it, so the bits between 0 and 1 were a bit closer to 1, and the bits between 0 and &#x2013;1 were closer to &#x2013;1.</p><p>My mathematical dust-gatherers had good intentions, saying things like &#x201C;doesn&#x2019;t squaring a number in [0,1] make it smaller, but in [1,&#x221E;) make it larger? Is that helpful?&#x201D; and &#x201C;doesn&#x2019;t a sigmoid function look kind of like an S? Your curve has S-looking things in it, maybe a sigmoid would be useful.&#x201D; But it turned out none of them had what I was looking for.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-hR2-zZx8uYrRAjst59ZMxA.png" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>Look at all these functions I don&#x2019;t&#xA0;want.</figcaption></figure><p>OK, so my math-rememberers weren&#x2019;t working. Time to go to first principles. If I had some function <em>squash</em>(<em>x</em>), which pushed values in [-1,1] away from 0 and towards the edges of the range, what would its properties be? First, I know that <em>squash</em>(0)<em> = </em>0<em>.</em> Also, <em>squash</em>(1)<em> = </em>1 and <em>squash</em>(&#x2013;1)<em> = </em>&#x2013;1. And then some values in between: <em>squash</em>(0.5) should be a bit closer to 1, say 0.6. And <em>squash</em>(&#x2013;0.5) should be a bit closer to &#x2013;1, by the same amount as 0.5 got pushed towards 1. I plotted out the points just like in 9th-grade.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-1KR_Rl0G1clXh9CDcNazqg.jpeg" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>Is that right, Mr.&#xA0;Scovell?</figcaption></figure><p>As I was looking at the picture I&#x2019;d drawn, a lightbulb went off in my head: that looks kind of like Photoshop&#x2019;s &#x201C;curves&#x201D; UI! A quick search and a helpful StackOverflow answer suggested Bezier splines, and from there I found <a href="http://cubic-bezier.com">cubic-bezier.com</a> which let me draw some curves like I wanted, and also some curves that I didn&#x2019;t want.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-Rgm9ype3DTrAtCnfVsr7-g.png" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>Not the S curve I was looking&#xA0;for.</figcaption></figure><p>Some <a href="https://github.com/Michaelangel007/easing">other pages</a> had &#x201C;ease-in-out&#x201D; functions for quadratic, cubic, quartic and so on, but I wanted to be able to tune the sharpness of the curve all the way from a straight line (no squashing at all) to a square wave (squash everything &lt; 0 to &#x2013;1, and everything &#x2265; 0 to +1), smoothly. I wanted a parameter I could tune to say how sharp the curve was. I wanted cubic-and-a-half, or quartic-minus-a-bit.</p><p>I didn&#x2019;t find the equation written down anywhere, so I figured it out. After a few dead ends, here&#x2019;s what I came up with:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-fIjOUr97p9rvWlPPDqJ34A.png" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>This function probably has some clever name given to it in 1928 by a Swiss guy, but I don&#x2019;t know&#xA0;it.</figcaption></figure><p><em>k</em> here is the &#x201C;squashedness&#x201D; of the curve, where 1 is a straight line, and &#x221E; is a step function.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-I2RbDZNojEOYc8mw7qiMyg.png" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>Squashedness levels, from 1 to&#xA0;5.</figcaption></figure><p>Feed the cosine into it, <em>et voila</em>!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Math-for-Game-Developers--Parameterised-Easing/1-KIVb5t4awESD0wgYPm_s9Q.png" class="kg-image" alt="Math for Game Developers: Parameterised Easing" loading="lazy"><figcaption>squash(3, cos(x)). No thanks to you, math-dust-gatherers.</figcaption></figure><p>I can imagine this sort of function being useful for all kinds of things other than squashing cosines. You could run it over a generated terrain to make the cliffs harsher, and valleys wider, or use it in an animation to control &#x201C;snappiness&#x201D;. I&#x2019;m going to use it to control light levels in a day-night cycle. If you use it, for making a game or otherwise, let me know on Twitter! I&#x2019;m <a href="https://twitter.com/nornagon">@nornagon</a> there, you should follow me.

</p>]]></content:encoded></item><item><title><![CDATA[How to finish something]]></title><description><![CDATA[
stop procrastinating
procrastinate more
 — — — (to avoid something more important)
focus
chip away at it
decide to do less
accept it
 ——…
]]></description><link>https://blog.nornagon.net/how-to-finish-something/</link><guid isPermaLink="false">5e81657b162871000117b667</guid><category><![CDATA[Creativity]]></category><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Thu, 22 Feb 2018 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p>stop procrastinating<br>procrastinate more<br>&#x200A;&#x2014;&#x200A;&#x2014;&#x200A;&#x2014;&#x200A;(to avoid something more important)<br>focus<br>chip away at it<br>decide to do less<br>accept it<br>&#xA0;&#x2014;&#x2014; (as it is)<br>publish it<br>smile at it<br>write about it<br>be proud of it</p><p>forget it

</p>]]></content:encoded></item><item><title><![CDATA[Synaptograph gets checkboxes]]></title><description><![CDATA[
(And some other stuff.)
]]></description><link>https://blog.nornagon.net/synaptograph-gets-checkboxes/</link><guid isPermaLink="false">5e81657b162871000117b67f</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Sat, 23 Sep 2017 00:00:00 GMT</pubDate><media:content url="https://blog.nornagon.net/content/images/downloaded_images/Synaptograph-gets-checkboxes/1-dx1GDykE9Hp1RBMK10yhdw.gif" medium="image"/><content:encoded><![CDATA[<h3 id="-and-some-other-stuff-">(And some other&#xA0;stuff.)</h3><img src="https://blog.nornagon.net/content/images/downloaded_images/Synaptograph-gets-checkboxes/1-dx1GDykE9Hp1RBMK10yhdw.gif" alt="Synaptograph gets checkboxes"><p>A year and a half ago I started working on a mind mapping tool called <a href="https://medium.com/@nornagon/mind-mapping-244d301fbadc">Synaptograph</a>, heavily inspired by the wonderful <a href="https://www.exobrain.co">Exobrain</a>, but quickly <a href="https://medium.com/@nornagon/the-doldrums-29a962e6ce26">ran out of steam</a>. This week, with joy, I picked it up again.</p><p>I keep notes of various kinds in about five different places right now. I write things on paper, I jot things down on my phone in Notes.app, I save articles I want to keep in Pinboard, I save papers and images in Dropbox, and I have more than a few NOTES.md files lying around in my code repositories. And lately, I&#x2019;ve been using Synaptograph to sketch out and explore new ideas. So that makes <em>six</em> places that I might have put something I wanted to remember.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/Synaptograph-gets-checkboxes/1-C9-Xble3aHoAuROEpanJpw.png" class="kg-image" alt="Synaptograph gets checkboxes" loading="lazy"><figcaption>Exploring an idea for a game in Synaptograph</figcaption></figure><p>Each of those six tools has its own advantages and disadvantages, but none really matches well with how my brain seems to want to arrange information. Paper gets lost, or isn&#x2019;t at hand when I need it. Pinboard is an abyss, as are Dropbox folders full of papers. I forget that NOTES.md exists. Notes.app is very linear.</p><p>I want Synaptograph to be a tool that meshes really well with the way I think, that lets me feel like I transferred part of my mind into an external medium. I want to be able to capture all the different things I&#x2019;m thinking about when I&#x2019;m working on something, whether it&#x2019;s something I need to remember to do, or an article I think might be relevant later and my notes on why, or a group of half-formed thoughts about a possible future direction, or a few paragraphs of explanation of how something could work.</p><p>It&#x2019;s not quite there yet, but this week I added two small features that move Synaptograph a little way in that direction.</p><p>The first is checkboxes. I use these on paper all the time, and having them in Synaptograph means that for simple things that don&#x2019;t need much in the way of sequencing, I can just put them directly into the mind map. To add a checkbox to a node, just write &#x201C;[ ]&#x201D; at the beginning of the text. It will automatically turn into a checkbox as soon as you press enter.</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/downloaded_images/Synaptograph-gets-checkboxes/1-dx1GDykE9Hp1RBMK10yhdw.gif" class="kg-image" alt="Synaptograph gets checkboxes" loading="lazy"></figure><p>I&#x2019;ve been using these a lot for tracking what I want to get done in Synaptograph itself, and it&#x2019;s been working great for that purpose. One thing I really like is having to-do items in a free-flowing two-dimensional layout, rather than a list. For personal projects I work on, there&#x2019;s very rarely a total ordering on tasks that need doing. A list forces you to choose what comes before what else. When you lay things out in two dimensions, it&#x2019;s much harder to put in fake ordering when there isn&#x2019;t any.</p><p>The second feature I added this week is links. Synaptograph now recognizes URLs, and will properly turn them into links, shortening them if necessary to keep the node text from stomping all over the map. Clicking on the icon next to the link takes you to the linked page, and clicking on the text lets you edit the URL (just like any other node).</p><figure class="kg-card kg-image-card"><img src="https://blog.nornagon.net/content/images/downloaded_images/Synaptograph-gets-checkboxes/1-yjedN1g5961vP_RUMj275Q.gif" class="kg-image" alt="Synaptograph gets checkboxes" loading="lazy"></figure><hr><p>There&#x2019;s a bunch more stuff I want to add, but these two small features are a good start towards making Synaptograph work more like my brain does.

</p>]]></content:encoded></item><item><title><![CDATA[TIL: L5 society]]></title><description><![CDATA[
The L5 society was a group in the 70's–80's that advocated for the colonization of space, in particular the Earth-Luna L5 Lagrange point…
]]></description><link>https://blog.nornagon.net/til--l5-society/</link><guid isPermaLink="false">5e81657b162871000117b672</guid><dc:creator><![CDATA[Jeremy Rose]]></dc:creator><pubDate>Tue, 12 Sep 2017 00:00:00 GMT</pubDate><media:content url="https://blog.nornagon.net/content/images/downloaded_images/TIL--L5-society/1-3hTcLhPvWsQPDBoLzrEJtg.png" medium="image"/><content:encoded><![CDATA[<img src="https://blog.nornagon.net/content/images/downloaded_images/TIL--L5-society/1-3hTcLhPvWsQPDBoLzrEJtg.png" alt="TIL: L5 society"><p>The <a href="http://www.nss.org/settlement/L5news/index.html">L5 society</a> was a group in the 70&apos;s&#x2013;80&apos;s that advocated for the colonization of space, in particular the Earth-Luna L5 Lagrange point. They were heavily inspired by Gerard O&#x2019;Neill&#x2019;s book <em>The High Frontier</em>, which described how technology already available at that time could be employed to build an orbital colony vessel.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/TIL--L5-society/1-3hTcLhPvWsQPDBoLzrEJtg.png" class="kg-image" alt="TIL: L5 society" loading="lazy"><figcaption>The indisputably rad logo of the L5&#xA0;society</figcaption></figure><p>O&#x2019;Neill proposed a cylindrical colony design, with a pair of 8km&#xD7;32km cylinders rotating in opposite directions at about 3rpm to approximate Earth&#x2019;s gravity. The counter-rotation would cancel out the gyroscopic force, helping to keep the station properly aligned with the sun.</p><p>(Though 3rpm sounds like it would be a little sickening! Look at that painting below, and imagine the sun zipping around all three of those window sections every 20 seconds. That&#x2019;s about 3 seconds from left to right of each section. I guess you&#x2019;d get used to it, but I bet new arrivals would spend a few days staring intently at their feet.)</p><p>Getting something that big out of Earth&#x2019;s atmosphere and gravity well would be next to impossible, so O&#x2019;Neill proposed building the stations using materials that were already conveniently placed&#x2014;on the Moon or from an asteroid. From there, you&#x2019;d ferry the stuff over to Earth-Luna L5 and construct the station in-situ.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://blog.nornagon.net/content/images/downloaded_images/TIL--L5-society/1-p6l-b7ychNE7VR5aNoM9Dg.jpeg" class="kg-image" alt="TIL: L5 society" loading="lazy"><figcaption>A cylindrical rotating space colony, proposed by Gerard O&#x2019;Neill in 1976. Painting by Rick Guidice, courtesy&#xA0;NASA.</figcaption></figure><p>The L5 society counts as one of its great victories the non-signing of the <a href="http://www.unoosa.org/oosa/en/ourwork/spacelaw/treaties/intromoon-agreement.html">Moon Treaty</a> by the US. I&#x2019;m not sure that&#x2019;s entirely a good thing&#x2014;I think humans should work together to enter space more-or-less unified, not scrabbling to seek profit and sell the Moon to the highest bidder. It turns out to have been more or less a moot point thus far, since launch costs and political iciness re: space exploration in the 80&apos;s up to the present have prevented any significant excursions, but with <a href="http://www.spacex.com/falcon-heavy">Falcon Heavy</a> set to fly in November and <a href="https://www.blueorigin.com/new-glenn">New Glenn</a> hot on its heels we might find we have renewed interest in regulating who can do what in space. A free-for-all doesn&#x2019;t seem like it would end well.</p><p>The L5 society is no longer, but in its place is the <a href="http://www.nss.org/">National Space Society</a>, advocating for the dream of living and working in space from its adorably 90&apos;s web page.

</p>]]></content:encoded></item></channel></rss>