<?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:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Massimog's massiblog]]></title><description><![CDATA[Videogames and things that are unrelated to Videogames (also Diorama Break news).]]></description><link>https://blog.massimogauthier.com</link><image><url>https://substackcdn.com/image/fetch/$s_!WlVN!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc58c93dc-201b-41d2-b463-6960be30646a_208x208.png</url><title>Massimog&apos;s massiblog</title><link>https://blog.massimogauthier.com</link></image><generator>Substack</generator><lastBuildDate>Tue, 19 May 2026 19:05:40 GMT</lastBuildDate><atom:link href="https://blog.massimogauthier.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Massimo Gauthier]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[massimog@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[massimog@substack.com]]></itunes:email><itunes:name><![CDATA[Massimo Gauthier]]></itunes:name></itunes:owner><itunes:author><![CDATA[Massimo Gauthier]]></itunes:author><googleplay:owner><![CDATA[massimog@substack.com]]></googleplay:owner><googleplay:email><![CDATA[massimog@substack.com]]></googleplay:email><googleplay:author><![CDATA[Massimo Gauthier]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[FOLIAGE SYSTEM, FOLIAGE SYSTEM!]]></title><description><![CDATA[YEEEAAAHHH!!! I LOVE MAKING TREES!!]]></description><link>https://blog.massimogauthier.com/p/foliage-system-foliage-system</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/foliage-system-foliage-system</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Sat, 16 May 2026 01:35:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8083a441-588d-4d96-9281-c1cd2c4d1d64_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Buckle up kids, time to learn how I made THIS:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;34772159-548e-40cb-aaf1-186203745265&quot;,&quot;duration&quot;:null}"></div><p>This will be the greatest devlog&#8212;in the series of devlogs I&#8217;m making for the <a href="https://www.kickstarter.com/projects/massimog/diorama-break">Diorama Break Kickstarter</a>&#8212;yet!!</p><h1>Early Stages</h1><p>Since I knew the demo&#8217;s environments would feature a lot of trees, I figured that having a way to &#8220;cheaply&#8221; place varied, animated foliage around would help us a lot with saving on environment art load and keeping the environments visually interesting<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. I also figured that, since the appearance of trees in real life is the result of fairly comprehensible stochastic/fractal processes, recreating something like that procedurally would be doable and likely produce results that felt &#8220;natural&#8221; without much additional effort.</p><p>The first steps involved developing a simple random algorithm for generating a &#8220;branch&#8221;:</p><ol><li><p>Start from a &#8220;root&#8221; node, and assign it a starting &#8220;decay&#8221; value and random direction.</p></li><li><p>Pick a new direction slightly randomly offset from the node&#8217;s direction. You will now create one or more child nodes. Roll a random value to decide first whether to &#8220;split&#8221;, &#8220;decay&#8221;, or do nothing:</p><ol><li><p>If you &#8220;split&#8221;, create two new child nodes slightly offset from the chosen direction in opposite directions, both with a &#8220;decay&#8221; value reduced by 1.</p></li><li><p>If you &#8220;decay&#8221;, create a new node in the chosen direction, with a decay value one less than the parent.</p></li><li><p>If you do nothing, do the same as b., but set its decay value the same as the parent&#8217;s.</p></li></ol></li><li><p>Repeat step 2 for every new node, unless its decay value is 0, at which point it is considered a &#8220;leaf&#8221; node and gets no children.</p></li></ol><p>Funnily enough, the resulting data structure would totally be described in computer science terms as a &#8220;tree&#8221;, making the normally abstract terms used to talk about said structures (branches, roots, leaves, etc.) hilariously literal in this case.</p><p>Anyway, once I had this structure, I could render it in game. All the trees rendered this way actually just use a single branch and leaf sprite, simply varying the size and rotation. With just the root node&#8217;s position, as well as the decay value and relative angle of it and every other node, I can derive the position and rotation of every sprite to draw by traversing the structure recursively (lower decay values have a smaller scale and offset, causing the tree branch to &#8220;taper off&#8221;, and decay values of 0 draw the leaf texture instead of the branch).</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;23fe36db-c30d-4852-89bb-8eb3859df2c0&quot;,&quot;duration&quot;:null}"></div><p>I continued to mess with the constants for random variables&#8212;stuff like angle ranges, starting decay value, chance of splitting/decaying&#8212;until I had something I was satisfied with for a single branch.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RcJm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RcJm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 424w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 848w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 1272w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RcJm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png" width="422" height="749" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:749,&quot;width&quot;:422,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:95606,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/197930609?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RcJm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 424w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 848w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 1272w, https://substackcdn.com/image/fetch/$s_!RcJm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F696eb797-2964-42c7-896e-4fa2a52e3265_422x749.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Adjustable variables for a single branch. The &#8220;e&#8221; stands for &#8220;editable&#8221;.</figcaption></figure></div><p>At that point, I began to work on animation. My idea would be to be able to assign a &#8220;wind force&#8221; to each node, and make them springy, so that they would sway back and forth. Wind force could then be applied at random throughout the branch to give the impression of random gusts. Thanks to the way I re-derive the position and rotation of every node every time the branch is rendered, force can be applied to the relative angle of a single node, and the angular change will &#8220;propagate&#8221; to all its children.</p><p>Overall this idea worked out, though it took hours of staring at footage of trees on windy days (as well as the trees outside my window) and <em>a lot </em>of tweaking to get just right<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m5L5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m5L5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 424w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 848w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 1272w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m5L5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png" width="357" height="116" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:116,&quot;width&quot;:357,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17158,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/197930609?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m5L5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 424w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 848w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 1272w, https://substackcdn.com/image/fetch/$s_!m5L5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd0962fa4-4d14-492f-9369-be584f43d9b9_357x116.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The four variables controlling wind animation. Might not seem like much, but each one can drastically affect the final animation behavior, making this something like a big 4D space to explore.</figcaption></figure></div><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;27690f1b-202a-4558-a8c2-1e3a05127f90&quot;,&quot;duration&quot;:null}"></div><h1>Full Background</h1><p>Now that I had nice-looking animated branches, I could begin populating the background. First step was to just spawn in a bunch of branches:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;b8edefd5-b949-4a5d-bea6-d7a17f26455d&quot;,&quot;duration&quot;:null}"></div><p>Not bad, but this was immediately taxing on my PC, so it was time for some optimization! At first I was just drawing every branch and leaf node individually, so the obvious thing was to construct a proper mesh <em>first</em>, then push the entire thing to the GPU in a single call.</p><p>Handling the final render positions in my own code had a few, uh, false starts&#8230;</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;e633ad7a-729b-4d86-a920-ec78487ff416&quot;,&quot;duration&quot;:null}"></div><p>Got it working eventually though, at which point I could start layering branches of different size and color to create more of an illusion of depth:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;33b8c202-1ee4-49ee-9d51-599f5f674f26&quot;,&quot;duration&quot;:null}"></div><p>And to complete the effect, a parallax offset for each layer:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;9e5b30d8-18cb-4f04-9275-956e93aa53b8&quot;,&quot;duration&quot;:null}"></div><p>Getting the exact distribution and branch size for each foliage layer also took some tweaking, but I&#8217;m pretty happy with the results!</p><h1>Final Touches</h1><p>And that&#8217;s where I left it, for the most part. Some more optimizations came after, particularly culling, though the effect is still not as performant as I&#8217;d like it to be. I think the big win will be in translating all the animation logic into shader code, so that a lot of that work can be done on the GPU and I don&#8217;t have to push these giant meshes (hundreds of thousands of vertices!) to it every frame, but that&#8217;ll have to wait until work on the full game begins.</p><p>We also ended up adjusting the colors to have the leaves match the branches, creating a more &#8220;silhouetted&#8221; look which distracts less from the foreground. Here&#8217;s that final iteration of the effect, straight from the demo:</p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;f1c5a6c0-67f3-4391-8b6e-c8ff5ee9eaa2&quot;,&quot;duration&quot;:null}"></div><p>&#8220;But wait!&#8221;, I hear you wail, &#8220;This is not the only animated foliage in the demo! What about the rest!?&#8221;</p><p>Ah, dear player, you will surely be raptured to hear that Diorama Break has, in fact, <strong>a second, entirely separate foliage system</strong> for foreground trees! That&#8217;s right!! But alas, my time here today is limited, so remember to <a href="https://www.kickstarter.com/projects/massimog/diorama-break/posts">vote for it as the next devlog topic in our latest backer update</a> to get another sweet, sweet foliage <em>fix. </em>Until next time!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Not having to animate this sort of thing by hand was the big win I was looking for here. Generating an articulated &#8220;mesh&#8221; in code would allow me to treat the animation process more like puppetry than drawing, which is much easier to automate. Also, initially, this was just meant for Stroma&#8217;s background, but this thinking was applied to foreground stuff later on too.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>One thing I was especially proud to get right was individual leaves sometimes wiggling around much more strongly, which is something you&#8217;ll notice is almost always present if you really stare at tree footage. To achieve this, leaves were assigned their own separate set of wind variables to be able to react to wind differently, as well as an extra variable that controls the extra chance of these &#8220;strong gusts&#8221; for them.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Why I Used a Custom Game Engine for my Indie Game]]></title><description><![CDATA[Part of a series of devlogs I&#8217;m making for the Diorama Break Kickstarter.]]></description><link>https://blog.massimogauthier.com/p/why-i-used-a-custom-game-engine-for</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/why-i-used-a-custom-game-engine-for</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Tue, 12 May 2026 22:54:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4cc9bb0f-56cc-49b4-b17e-d4bdb2d1a809_840x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Part of a series of devlogs I&#8217;m making for the <a href="https://www.kickstarter.com/projects/massimog/diorama-break">Diorama Break Kickstarter</a>.</em></p><p>Long-time subscribers will remember <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non">the series of devlogs I did a couple years ago over the course of building my own custom game engine</a>. A lot of my thinking on the subject is captured in that original post, but now, after over a year of actually using the engine and producing a successful game demo with it, I thought it would be worth revisiting.</p><h1>Why Use a Custom Engine?</h1><p>The &#8220;common wisdom&#8221; around this topic often boils down to this idea that creating a custom engine as a solo dev or small team will necessarily suck up half a decade without any actual <em>game </em>to show for it. While there are a few anecdotal horror stories to this effect, for the most part <strong>this is a myth</strong>. Use of third-party engines like Unity, Unreal, or Godot was nowhere near a dominant practice until the mid-2010s. Many of the most influential indie games of all time&#8212;games like Braid, FTL, and Terraria&#8212;were all made with custom engines in just 1 to 3 years. And thanks to the release of new and friendlier low-level languages and frameworks like Odin, Raylib, SDL3, etc. over the past decade and a half, this style of game development is easier and more approachable than ever!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> My own experience involved getting fed up with the limitations of Game Maker, giving myself half a year to replicate all the basic features I liked from it in my own software (and add a few I thought were sorely missing), and managing to get it all done in just about five months!</p><p>There are a few caveats of course. It&#8217;s not something I would recommend to total beginners; without experience actually <em>using </em>an existing engine you wouldn&#8217;t even really know what to build in the first place. Having at least one major project under your belt, ideally one made for commercial release, will give you indispensable insight into what you&#8217;ll actually need in terms of tools. 3D is also a much greater challenge compared to 2D. While I feel confident that I could tackle a custom 3D engine now, after my experience building my 2D engine, even at the onset I recognized that trying to do something 3D from the start would have added waaay more complexity and potentially spiraled into something unsustainable. And if you&#8217;re angling to compete with high-fidelity AAA graphics, it&#8217;s not clear to me that as a solo dev going custom is viable in at all the same way that it is for something 2D or stylized.</p><p>But I still haven&#8217;t really answered the question <strong>&#8220;why bother&#8221;? </strong>If third-party engines developed by all these well-resourced companies and communities are just sitting there for the taking, why put in all this extra work reinventing the wheel? At the core of it, it&#8217;s perhaps a sense of pride and self-reliance, wanting to have the agency, deep understanding, and control that building my own tools affords me. But I can also list a lot of practical advantages:</p><ul><li><p>Third-party engines can be extremely bloated, with years of feature creep, abandoned functionality, and &#8220;legacy support&#8221; taking their toll on usability and the ease of learning the engine. When building your own tools, you can choose exactly what you do and don&#8217;t need, and you&#8217;ll have a full understanding of what&#8217;s available to you once you get to actually building your game.</p></li><li><p>Most third-party engines are built to be extremely general-purpose, in order to give all users the option to create almost any sort of game. That often means that the tools you&#8217;re given won&#8217;t be <em>quite </em>suited to your specific needs, which can range from them just being slightly annoying to work with, to requiring enormous additions and workarounds (which are often more work to integrate with existing engine bloat than it would be to just build the whole tool from scratch in your own clean ecosystem). More specialized engines like RPGMaker and Ren&#8217;Py exist, but they&#8217;re even more susceptible to the next problem&#8230;</p></li><li><p>If a third-party engine doesn&#8217;t support a feature or have a tool you need for your game, it&#8217;s often a serious problem. Building the tool from scratch and integrating it with the engine can range from extremely time-consuming to outright impossible, especially if the engine is closed-source. With your own engine, you built everything anyway, so one more feature is just that. Much<em>, much </em>easier.</p></li><li><p>Similar to the above point, if a third-party engine <em>does </em>technically support a feature but it&#8217;s <em>broken </em>in some way (either buggy or just unfinished), you&#8217;ll often be caught between trying to fix it yourself, hoping and waiting for the engine developers to fix it, or just working around it in a way that makes your game worse; all risky and annoying options. With your own tools, you can of course just fix them yourself as easily as you built them in the first place.</p></li><li><p>Many third-party engines will encourage the use of tools and scripting languages that offer very limited control of the exact behavior of your final program, especially when it comes to things like memory layout. This might make things easier when starting out, but will eventually spiral into you having performance issues you have no easy way to solve (or even properly diagnose). Certain designs will even be outright impossible to achieve without the ability to finely optimize your game; Noita is a game that simulates <em>every single pixel </em>on screen as a powder-like physics object, something that feels to me like it would be impossible or at least <em>unbelievably </em>onerous to do in an engine you didn&#8217;t have complete control over<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p></li><li><p>This is more of an issue diffused across the industry, but widespread use of third-party engines, among other things, has caused an observable decrease in &#8220;diversity&#8221; in modern games. When you&#8217;re forced to build everything yourself, you&#8217;ll end up making a bunch of tiny idiosyncratic decisions about things like physics, lighting, rendering, etc. that cause your game to feel &#8220;unique&#8221; in subtle and not-so-subtle ways. When everyone is instead reaching for the same cookie-cutter solutions that engines offer for basic problems, designs and game feel are pushed more in the direction of what is easy to do in these engines, and many games end up with, for example, &#8220;Unity smell&#8221;. While it&#8217;s possible to get around this by carefully replacing and tuning every aspect of an engine, at what point does it not just become less effort to do everything from scratch?</p></li><li><p>Many (but not all) third-party engines demand fees, either fixed fees for access to exporters for certain platforms, or in the form of a portion of profits from successful enough commercial projects that rely on them. Not entirely unfair of them to want to be paid for their work, but avoiding these fees can be a compelling reason to stick with your own tools if you plan to develop a large commercial game.</p></li></ul><h1>How&#8217;s it Going?</h1><p>Again, <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non">my old devlog series</a> is probably the best place to go if you want to get more into the nitty-gritty of how I actually built the engine, but here&#8217;s how things have been going in the past year and a half for those who have read it:</p><p>In general, I&#8217;ve probably become even more handmade-pilled. The original engine had a few third-party libraries and tools in the pipeline that were so annoying that I&#8217;ve since stripped them out and replaced them with my own solutions<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. I&#8217;ve definitely gotten the itch to try and replace <em>every </em>third-party library and tool once I have more time to work on the engine, though FMOD and SDL are still worth keeping in my opinion<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>.</p><p><a href="https://odin-lang.org/">Odin</a> has also continued to be a blast to use, no major complaints there. Especially now that I&#8217;ve explored most of the features of the language, I&#8217;ve come to really appreciate the general philosophy it has of only trying to give you one <em>great </em>tool per problem you&#8217;re likely to encounter. Avoiding choice paralysis and footguns like that is great for my mental bandwidth, and I can always feel confident when I encounter a new problem that, if it can be solved with just Odin, there&#8217;ll be a straightforward way to do so (and this is indeed true of most problems I&#8217;ve encountered so far). Probably the biggest thing missing in my opinion is some way to automatically generate symbols (such as by reading asset directories), something I have to rely on external &#8220;metaprogram&#8221; scripts to do, but I definitely get why Bill can&#8217;t<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, say, just quickly whip up a robust metaprogramming system to cover cases like this.</p><p>The biggest addition since I got all the basic engine features done has probably been the custom <strong>stage editor </strong>for Diorama Break. Having the ability to just whip up any feature I want for this tool has been great for producing something useful and ergonomic, though I do wish other members of the team would take advantage of this more and pester me about desired fixes and features. It&#8217;s a bit embarrassing to leave the tool in their hands for a while then try it out and notice a bunch of places where I left things horribly unfinished!! Anyway, there&#8217;s a lot I could talk about here, but I&#8217;ll leave it for a future devlog.</p><p>Overall, I don&#8217;t think I&#8217;ll ever be inclined to return to a third-party engine. The ease of use and sense of security all this control gives me has been fantastic, and especially now that we&#8217;re well over the initial development hump, the return on investment is really starting to show. I was able to implement our entire localization system in just a few days<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a>, something which I&#8217;ve heard other developers say took them weeks if not <em>months </em>to do.</p><p>I also feel like I&#8217;ve grown tremendously as a programmer, maybe not as drastically as after the initial engine development period, but every day brings more improvement to my skills and confidence to just manifest whatever tool I need to knock down the problems in my path<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>. Sometimes it takes a little longer than expected, much to my producer&#8217;s frustration, but the results in Diorama Break&#8217;s demo hopefully speak for themselves. There&#8217;s still a ton to work on though, <a href="https://www.kickstarter.com/projects/massimog/diorama-break">so let&#8217;s keep that Kickstarter momentum going!</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Not to mention having LLMs available for research and personalized tutorials.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>And indeed, the Noita team developed a custom engine expressly for the project, even naming it &#8220;Falling Everything&#8221; in reference to this central technical design goal.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Most notably, the texture packing system for sprites, which is now entirely custom.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Though I do want to upgrade to SDL3. There&#8217;s also no getting around using the Steamworks SDK, but that has been a surprisingly pleasant API to work with and I don&#8217;t really have any reason to want it gone.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>And doesn&#8217;t want to.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>And this is despite menus not <em>at all </em>being built with localization in mind (whoops)</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p>Even ones you might not expect, like scripts to auto-collate some of the graphics for our Kickstarter page.</p></div></div>]]></content:encoded></item><item><title><![CDATA[How I Got My Game To Kickstarter]]></title><description><![CDATA[Part of a series of devlogs I&#8217;m making for the Diorama Break Kickstarter.]]></description><link>https://blog.massimogauthier.com/p/how-i-got-my-game-to-kickstarter</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/how-i-got-my-game-to-kickstarter</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Wed, 06 May 2026 00:23:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ZS1i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Part of a series of devlogs I&#8217;m making for the <a href="https://www.kickstarter.com/projects/massimog/diorama-break">Diorama Break Kickstarter</a>.</em></p><p>&#8230;and said Kickstarter is proceeding smoothly, with 50k CAD raised at this point. Our goal&#8217;s set at 95k, and for those less familiar, it&#8217;s practically certain at this point that we&#8217;ll be able to hit it. A huge victory! Diorama Break is well on its way to being a big commercial release! So, how did we get to this point?</p><h1>Early Ideas</h1><p>The first ideas for Diorama Break came around early 2018, mainly after having played <a href="https://store.steampowered.com/app/420530/OneShot/">OneShot</a>. The idea of an RPG where you could talk directly to the protagonist the whole time was a fascinating one, and something I thought could be interesting even outside of OneShot&#8217;s more limited scope and adventure/puzzle gameplay style. More generally, my teenage years (2013-2019) were something of a golden age for this &#8220;sincere postmodern&#8221; style of interactive storytelling, and the impact projects like Undertale and The Stanley Parable had on me had left me wanting to try my own hand at that sort of storytelling<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. My exact memories of this time are fuzzy, but I distinctly remember starting out with a strong vision of the game&#8217;s opening as well as its climax, and filling in the rest from there in my head whenever I had spare time to reflect on it.</p><p>The combat system was initially an entirely separate idea for a different game, but as it happens I realized it would fit really well as a JRPG combat system, and so gradually grafted it on to the core concept.</p><p>At the time, I was still in school, and ended up building up the idea as something I could work on solo after graduating. My final project at the time though was also a simple RPG, and I definitely structured things such that I could reuse a lot of the technical work from that after it was done.</p><h1>First Prototype</h1><p>After a tumultuous graduation in May 2020 (note the timing), I spent some time trying to land a job in Montreal&#8217;s indie scene. After a few months of nothing though, I figured I&#8217;d have to get busy with something on my own, and set out to create the first prototype for the gameplay. I even took the time to document the process in a series of polished devlogs (real Massimoheads will know), which you will NEVER find. </p><p>That process took about a year, from July 2020 to July 2021, of coding, art, and videomaking. At the end of it I had an ok-looking prototype featuring over a dozen stages, a bunch of wacky mechanics, and an <em>insane </em>learning curve. Many things differ in that system from today&#8217;s demo, for example:</p><ul><li><p>No turns. You had to define unit actions <em>every single step</em>. As soon as a unit became free, you could commit a new action. As you can imagine, this was pretty tedious, and even more confusing for people used to traditional tactics systems (many tried to attack immediately and got interrupted by faster enemies).</p></li><li><p>Movement was &#8220;free&#8221;, i.e. as long as a unit was available you could move <em>and </em>commit an action on the same step.</p></li><li><p>Enemies would not show their future &#8220;plans&#8221;, instead, for the most part, you were expected to bait them into committing an action, then avoid it and counterattack.</p></li><li><p>The point of this prototype was to test the limits of the combat system, so battles near the end featured up to about a dozen units and many wacky actions were implemented. The most egregious example was an action attempting to emulate a &#8220;reflector&#8221;-style attack, which would &#8220;attack a small area around the user for 3 steps and prevent all damage and hitstun from attacks, but ONLY if the attacker was over 8 tiles away&#8221;. Needless to say this was kind of a nightmare to explain to playtesters.</p></li><li><p>The average unit would take up 4x4 tiles, rather than the current demo&#8217;s 3x3. We ultimately changed this since odd-numbered unit sizes allow units to have a well-defined &#8220;center&#8221;.</p></li><li><p>Virtually no narrative was featured, just units fighting on islands.</p></li></ul><p>Ultimately though, the combat felt fun enough to give me the confidence to move forward with the idea in the full game. The experience also taught me that doing Youtube at the same time as making a game is <em>really freaking time-consuming </em>and mostly just distracted me from actually working on the thing I cared about.</p><p>Anyway, at the same time that I was working on this, my career as a contract indie game programmer kicked off, so I ended up putting the project down for a bit in late 2021 to focus on that. This was also around the time that ANTONBLAST was beginning development, and helping get <em>that </em>Kickstarter was exciting enough to keep a lot of my spare attention.</p><h1>Getting the Team Together</h1><p>Over the next couple years, I kept an eye out for opportunities to really get the project started, and worked on concretizing a lot of the project&#8217;s scope and worldbuilding. Working on Antonblast had sparked within me a desire to not compromise and make something smaller or less polished for my own project, so the plan I worked out ended up being a lot bigger than something I could take on by myself.</p><p>With said plan in mind, the first thing I resolved to do, before anything else, was nail down an excellent art director. Getting someone who could not just support the project in terms of producing assets but really create and maintain a concrete and cohesive vision for how the <em>entire </em>project should look was a must-have to avoid falling into the trap of hiring a bunch of siloed artists whose work might be good on its own but would not end up cohering. While I eventually ended up taking on some of this job myself simply in my role as Director, at the time I considered this not my area of expertise, and therefore something I ought to hand over completely to someone more qualified.</p><p>To this end, and to help build a shortlist of potential artists of all stripes, I constructed a bot to scrape Twitter<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> for game artists looking for work that matched the style and interests I was looking for<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. While this did help me get my list started, I ended up finding <strong>SaKo </strong>through other means (I was scrolling follower lists, saw a profile picture I liked, and looked up who drew it). After a few months of talking back and forth and commissioning some concept art from him, I convinced him to join the project and help me recruit the rest of the team.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!a5x5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!a5x5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 424w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 848w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 1272w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!a5x5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png" width="852" height="480" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/baca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:480,&quot;width&quot;:852,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:37551,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196581889?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!a5x5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 424w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 848w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 1272w, https://substackcdn.com/image/fetch/$s_!a5x5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbaca6eb2-da7a-4caf-9991-6d52c5ecf64f_852x480.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">The first(ish) piece of Diorama Break art not made by me.</figcaption></figure></div><p>Once SaKo was on board, around the start of 2024, &#8220;pre-production&#8221; on the demo could finally start ramping up. Production on Antonblast was slated to finish by the end of the year. Once that was done, I&#8217;d be free to move full time onto the full production of the Diorama Break demo without missing a beat. My plan began to solidify, by the end of 2024 I&#8217;d have to:</p><ul><li><p>Get a team of artists to commit to working on the game.</p></li><li><p>Obtain funding to pay those artists for the duration of the demo&#8217;s production.</p></li><li><p>Plan out all assets that would be needed along with time and budget estimates.</p></li><li><p>Define a schedule and art pipeline to keep production running smoothly during the busy period.</p></li><li><p>Create the game engine for the demo.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></p></li><li><p>Work with SaKo to complete as much concept material for Chapter 1 and the rest of the game as possible to give people an idea of what we&#8217;d be working towards.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZS1i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZS1i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 424w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 848w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 1272w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZS1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png" width="816" height="473" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:473,&quot;width&quot;:816,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64415,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196581889?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZS1i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 424w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 848w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 1272w, https://substackcdn.com/image/fetch/$s_!ZS1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F86271810-a3e2-4f06-b6df-8f728dc85ee8_816x473.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Early aggregated estimate of how many work hours would have to be spent per asset type.</figcaption></figure></div><p>Ultimately, pre-production ended up going fairly smoothly, with most artists we reached out to agreeing to join the project between November and January 2025. I applied for <a href="https://cmf-fmc.ca/">CMF </a>funding around March 2024, and was ultimately rejected after the 6 month review process, but the silver lining here is that this pushed me to recruit people very early, which made it a lot easier for them to agree (&#8220;I have a job lined up now!&#8221; and not &#8220;I&#8217;m too busy to join this project immediately&#8221;). I&#8217;m fortunate enough that despite the funding from the CMF falling through, I was still able to cover costs for the demo&#8217;s development with my own savings and money borrowed from family; this sort of endeavor at this level of ambition is not something I think would be easy for most people to do and I&#8217;m incredibly grateful to be in a position where I was even able to take the risk in the first place.</p><p>One thing that might surprise you is that most team members on Diorama Break, including SaKo, were just people I cold-called after seeing their portfolios, usually through twitter DMs or their business contacts. I had prepared a couple-page document pitching the project and explaining my goals, timelines, and remuneration structure; combined with SaKo&#8217;s concept work this ended up convincing most people to come on board. Let it be known then, if you come to them with a mutually beneficial offer, people are quite willing to hear you out! The most exciting example of this was Mariru; I was originally hesitant to reach out since I couldn&#8217;t really speak Japanese, but I gave it a try anyway and it worked out great! I even managed to set up a bot in our work discussion server to translate messages back and forth so that he could easily participate like anyone else<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>.</p><p>Antonblast ended up taking a little longer to release than expected, and I had a fun couple of months where I had to stay in a temporary SRO in between moving houses while finishing that <em>and </em>at the same time getting Diorama Break ready for full production. I feel like I have terrible luck when it comes to the timing of big life events like this&#8230; got through it though, and proper production got started in December 2024.</p><h1>Demo Production</h1><p>This part of the project is both easier to talk about for being fresh in memory and harder for not having as much distance from it and the hindsight that comes with that. The original production timeline ended up being <em>extremely </em>optimistic, I had modeled it off Antonblast&#8217;s Kickstarter demo production, which only took 4 months. Turns out that making a content-heavy JRPG with a completely fresh team and half-finished tools takes a <em>little </em>longer than that. One thing we were really struggling with for a while was satisfactorily laying out the environment art with the right perspective, fortunately though I was able to recruit Mirrorfloria in June after attending a local pixel art workshop she was running and deeming her a good fit for the job. She managed to right that aspect of production <em>quick</em>, something I&#8217;ll be eternally grateful for.</p><p>Anyway, I&#8217;ll spare you more recountings of embarrassing production mistakes I made early on. I&#8217;m at least relieved that we only went over-time and not over-<em>budget </em>(although some sources of income ended up not coming in, or coming in later than expected, so that still felt quite stretched near the end and contributed to us launching the Kickstarter so soon after the demo launch). Here&#8217;s roughly what production milestones we hit and when:</p><ul><li><p><strong>February 2025</strong>: All basic tooling and game mechanics (dialogue, stage editor, combat system, overworld movement) functional. Models and concept art for all major characters complete.</p></li><li><p><strong>May 2025: </strong>First non-combat stage (Pro&#8217;s room) implemented and first cutscene done.</p></li><li><p><strong>June 2025: </strong>First playtest demo shown at a local event (featuring just the combat tutorial).</p></li><li><p><strong>August 2025: </strong>Most Stroma Village stages complete (no NPCs), teaser trailer released, demo build shown at PAX West (featuring all critical-path content from the intro to the end of the combat tutorial).</p></li><li><p><strong>October 2025:</strong> Finished draft of all remaining critical-path dialogue and cutscene code.</p></li><li><p><strong>December 2025: </strong>&#8220;Gameplay reveal&#8221; trailer, Diorama Break appears in the &#8220;Choose Wisely&#8221; Steam festival.</p></li><li><p><strong>January 2026: </strong>Finished all dialogue.</p></li><li><p><strong>February 2026:</strong> Finalized all cutscenes and stages, demo releases in open beta.</p></li><li><p><strong>April 2026: </strong>Demo releases on Steam with new trailer and several polish improvements. Kickstarter launch.</p></li></ul><p>And now here we are! While the time it took to get this demo out the door might seem daunting in the context of the full game&#8217;s eventual production, with the lessons learned, the foundation we set up through the demo&#8217;s production, and the financial cushion from the Kickstarter, we&#8217;ll be more than efficient enough to deliver on time. Though whether we get to <em>that </em>starting line is now in your hands! <a href="https://www.kickstarter.com/projects/massimog/diorama-break">24 days to go, let&#8217;s get it done!</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>This might surprise some, but my initial ideas for the game came <em>before </em>deltarune&#8217;s first chapter was released. For spoiler reasons I won&#8217;t specify exactly what I&#8217;m talking about, but people can take educated guesses. To be fair though, many of the ideas I&#8217;m gesturing at were present in Undertale, just a lot more in the background.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>This was before the API changes which would make this much harder nowadays, though most of the scraper&#8217;s work was still done through a webdriver.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>I fortunately already knew dante gofar was exactly who I wanted to do the music (I even pitched him the project in person at PAX East in 2023), so I didn&#8217;t have to build a shortlist of musicians too.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Game Maker was my fallback here, but you can see <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non">my series on the development of that engine</a> for how I was feeling about that fact at the time.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>Which really feels like it should be a first-class feature of most chat apps, language barriers don&#8217;t need to exist anymore!</p></div></div>]]></content:encoded></item><item><title><![CDATA[How I Made a Game Dialogue System Better than Anything I Could Find Online]]></title><description><![CDATA[Part of a series of devlogs I&#8217;m making for the Diorama Break Kickstarter]]></description><link>https://blog.massimogauthier.com/p/how-i-made-a-game-dialogue-system</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/how-i-made-a-game-dialogue-system</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Sun, 03 May 2026 00:51:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5e9dd4df-9926-4625-a353-63378b2914e1_3840x2160.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Part of a series of devlogs I&#8217;m making for the <a href="https://www.kickstarter.com/projects/massimog/diorama-break">Diorama Break Kickstarter</a>.</em></p><p>There&#8217;s a distinct sort of dialogue style you&#8217;ll see in a <em>lot </em>of RPGs and other games, where one line gradually appears after another inside a textbox, sometimes with a portrait to go along with it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z9ha!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z9ha!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 424w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 848w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 1272w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z9ha!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif" width="512" height="446" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:446,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:394834,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z9ha!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 424w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 848w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 1272w, https://substackcdn.com/image/fetch/$s_!z9ha!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F17ebfdf3-15f6-4a92-9511-8c9e4351349a_512x446.gif 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Many indie developers, then, seek to emulate this style for their own games. A very common and straightforward way one might think to do this<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> is to just write every individual line of dialogue directly into their code, usually inside some sort of linear structure. <a href="https://en.wikipedia.org/wiki/Undertale#Development">Toby Fox even said he was partly inspired to create Undertale and its dialogue system after reading about &#8220;array data structures&#8221;</a>. You can then render your textbox, and one line of dialogue at a time, showing the next line every time the player gives the input. This has a number of limitations though:</p><ul><li><p>It doesn&#8217;t account for branching dialogue.</p></li><li><p>It makes it difficult to swap out lines conditionally, such as when changing the game&#8217;s language.</p></li><li><p>It forces non-programmers to dig into the code files to change dialogue.</p></li><li><p>It alone can&#8217;t account for style, like italics, text coloration, text scroll effects, and more.</p></li><li><p>It adds a lot of boilerplate code syntax that isn&#8217;t strictly necessary.</p><p></p></li></ul><p>A lot of online tutorials therefore recommend you move all your dialogue into spreadsheets:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pyux!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pyux!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 424w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 848w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 1272w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pyux!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png" width="1456" height="814" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:814,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Free game writing resources to download&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Free game writing resources to download" title="Free game writing resources to download" srcset="https://substackcdn.com/image/fetch/$s_!Pyux!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 424w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 848w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 1272w, https://substackcdn.com/image/fetch/$s_!Pyux!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a2e175-3e34-499c-9ccf-92f64014928e_1995x1115.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">As you can see, annotations and per-line metadata become a lot easier to add.</figcaption></figure></div><p>This fixes a lot of the issues above, and is a lot more &#8220;industry-standard&#8221;. In general, the idea that you should treat dialogue as a data asset that you work on separately from your code (like sprites or audio) is correct. Even if this alone can&#8217;t handle branching dialogue, being able to load and refer to dialogue as data like this makes it a lot easier to implement such a system.</p><p>However, <strong>this still isn&#8217;t great! </strong>Spreadsheets are a very general-purpose tool and weren&#8217;t exactly designed with <em>scriptwriting </em>in mind, and especially not interactive scriptwriting with branching paths, dialogue flags, and potentially very complex conditional behavior based on the state of a bunch of game data. They might work ok if you have all your dialogue already mapped out and ready to go, but creating and editing all that dialogue in the first place can quickly spiral into an overcomplex nightmare!</p><p>What tools, then, are more precisely engineered for the task? Well, Disco Elysium, a game with one of the most complex dialogue systems in recent memory, uses a tool called <a href="https://www.articy.com/en/">Articy</a>:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oCUz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oCUz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 424w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 848w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oCUz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg" width="1456" height="706" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:706,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Disco Elysium &#8211; Articy&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Disco Elysium &#8211; Articy" title="Disco Elysium &#8211; Articy" srcset="https://substackcdn.com/image/fetch/$s_!oCUz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 424w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 848w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!oCUz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6961a4da-178b-478a-b2e8-86e4c79100d4_1905x924.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>You can glean from the screenshot that this is sort of a cross between a scriptwriting tool and a visual scripting system, allowing the devs to express branches, set flags, have conditions and jumps, define dialogue styling, and more, all from a single editor. It might take a little more legwork to get it to talk to your game code, but it seems well worth it for the resulting ease-of-use when editing. And if it seems a bit pricy or daunting, similar open-source alternatives like <a href="https://twinery.org/">Twine</a> exist.</p><p>If that sounds cool to you, Articy might be the place to end your search, and I <em>had </em>seriously considered giving it a shot for Diorama Break, but something about visual scripting tools has always put me off. Being able to just write out my branching dialogue in a simple text editor, same as any cinematic or theatrical scriptwriter, had been the holy grail of ergonomics for me. I wanted <em>that</em>. And there really didn&#8217;t seem to be a tool that came up in my research catering to me so&#8230; why not make my own?</p><h1>Designing the System</h1><p>Since I was looking to end up with a workflow where the bulk of dialogue &#8220;content&#8221; is just line-by-line text that can be stored and edited like any text file, I decided the right tool for the job was a <strong>markup language</strong>.<strong> </strong>That is, a language where text content lives alongside &#8220;code-like&#8221; annotations, which a renderer can use to produce a final document output. The most famous example of one is undoubtedly HTML, which determines the layout of pretty much every web page on the internet (you can press F12 right now to see the HTML behind this page!) Full disclosure, I had already experimented a bit with this sort of thing in school and for the Diorama Break prototypes, but now I was set on making something truly polished that could comfortably support me through the development of a whole JRPG.</p><p>So the basic plan was to design a language of annotations that I could add to my dialogue text to express things like branching, text style, and more. I then need to build an <strong>interpreter and renderer </strong>in my engine that can read the resulting text files and display the appropriate dialogue and choices, as well as an <strong>editor </strong>that can display these annotations in a way that&#8217;s easy to parse at a glance and edit.</p><p>One very popular markup language right now is <strong>Markdown</strong>. Lauded for its simplicity, it barely feels like a &#8220;language&#8221; at all, just a very simple set of rules you can use to write out documents with headings, images, basic text styling, and more, all by hand.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nDqq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nDqq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 424w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 848w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 1272w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nDqq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png" width="1456" height="914" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:914,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;macos - github flavored markdown editor for osx - Super User&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="macos - github flavored markdown editor for osx - Super User" title="macos - github flavored markdown editor for osx - Super User" srcset="https://substackcdn.com/image/fetch/$s_!nDqq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 424w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 848w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 1272w, https://substackcdn.com/image/fetch/$s_!nDqq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3da7b0e3-e713-41d9-95fc-c2092cb9bb4d_2276x1428.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Its popularity gave it something I could spin to my advantage: a whole ecosystem of text editors that support it natively. This solved a big problem for me: rather than build a text editor from scratch with all the extra features I would need, I could use an existing Markdown text editor, write my annotations with markdown syntax, then write my <em>interpreter </em>in a way that it could parse that markdown into in-game dialogue, basically cutting the work in half!</p><p>For my editor of choice, I ended up going with <a href="https://obsidian.md/">Obsidian</a>, since I was already familiar with it for note-taking.</p><div><hr></div><p>To recap then, I was looking to build my markup language with these features:</p><ul><li><p>Simple text as the backbone. One line of plain text in the document = one line/box of dialogue in-game.</p></li><li><p>Stylistic markup for bold, italic, and colored text.</p></li><li><p>A simple way to express nested branching dialogue with both conditional checks (&#8220;if statements&#8221;) and player dialogue choices.</p></li><li><p>Ability to jump to different points in dialogue for more complicated branching behavior.</p></li><li><p>Ability to set flags.</p></li><li><p>Ability to call arbitrary engine functions (for more complicated behavior, e.g. starting cutscenes).</p></li><li><p>Ability to set the speaker&#8217;s profile picture and have it be visible in-editor.</p></li></ul><p>Here&#8217;s the syntax I ultimately settled on:</p><h3><strong>Styling</strong></h3><p>This one was a no-brainer. Markdown supports using asterisks for *italic*, **bold**, and ***bold italic*** text. Colored text was a little harder, but I ended up using an Obsidian plugin that will color the text you highlight by inserting a special HTML tag:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!l2tb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!l2tb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 424w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 848w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 1272w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!l2tb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png" width="429" height="35" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:35,&quot;width&quot;:429,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3955,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!l2tb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 424w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 848w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 1272w, https://substackcdn.com/image/fetch/$s_!l2tb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F24ccf2e3-f0f2-4607-922c-3dc1af20d7db_429x35.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pBgf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pBgf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 424w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 848w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 1272w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pBgf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png" width="110" height="31" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:31,&quot;width&quot;:110,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:851,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pBgf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 424w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 848w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 1272w, https://substackcdn.com/image/fetch/$s_!pBgf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa55588a-7cc6-40b1-a1b2-bb2d45bfa327_110x31.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>Jumps</h3><p>For jumping between different points in dialogue, I decided to use Markdown headings (which I call &#8220;labels&#8221; in this context). This lets me naturally segment the file in a way that looks nice in-editor (and lets me fold up segments). By inserting a Markdown link, I can tell the dialogue to jump to a new label, and as a nice bonus I can click on said link in-editor to jump there too!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4UX9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4UX9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 424w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 848w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 1272w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4UX9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png" width="721" height="697" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:697,&quot;width&quot;:721,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51972,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4UX9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 424w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 848w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 1272w, https://substackcdn.com/image/fetch/$s_!4UX9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68b76c74-242c-46eb-978e-5945b8c8503b_721x697.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>Branching Dialogue</h3><p>By using Markdown quote syntax, I can create a pretty nice looking &#8220;dialogue tree&#8221;. This will pop up a question box the player can use to give a response:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iPb0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iPb0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 424w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 848w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 1272w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iPb0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png" width="695" height="441" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/29ecea87-664a-4912-892f-bc70fe57a332_695x441.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:441,&quot;width&quot;:695,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30271,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iPb0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 424w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 848w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 1272w, https://substackcdn.com/image/fetch/$s_!iPb0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F29ecea87-664a-4912-892f-bc70fe57a332_695x441.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It&#8217;s even possible to nest these choices and jump to and out of them using labels:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xxdx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xxdx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 424w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 848w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 1272w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xxdx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png" width="448" height="622" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac386225-f28c-441c-8b09-33908f85dd77_448x622.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:622,&quot;width&quot;:448,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32471,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xxdx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 424w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 848w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 1272w, https://substackcdn.com/image/fetch/$s_!xxdx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac386225-f28c-441c-8b09-33908f85dd77_448x622.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here&#8217;s what that looks like without Obsidian&#8217;s prettification:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GmRk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GmRk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 424w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 848w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 1272w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GmRk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png" width="420" height="591" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:591,&quot;width&quot;:420,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34578,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GmRk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 424w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 848w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 1272w, https://substackcdn.com/image/fetch/$s_!GmRk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea92ad7-1906-44ce-a687-0ca2b3a1ee1a_420x591.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you&#8217;ve played Diorama Break, you&#8217;ll know it also features &#8220;optional&#8221; dialogue choices, called &#8220;interjections&#8221;. I mark these just by adding a &#8216;!&#8217; at the start of the first choice. If the player ignores the choice, the dialogue will just skip past the entire choice block.</p><h3>Conditionals and Commands</h3><p>By using Markdown&#8217;s backtick syntax, intended for showing code blocks, I can separate normal text from basic scripting logic I want to insert. The first thing this can be used for is conditional blocks (also nestable):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5__H!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5__H!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 424w, https://substackcdn.com/image/fetch/$s_!5__H!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 848w, https://substackcdn.com/image/fetch/$s_!5__H!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 1272w, https://substackcdn.com/image/fetch/$s_!5__H!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5__H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png" width="612" height="478" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:478,&quot;width&quot;:612,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32441,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5__H!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 424w, https://substackcdn.com/image/fetch/$s_!5__H!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 848w, https://substackcdn.com/image/fetch/$s_!5__H!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 1272w, https://substackcdn.com/image/fetch/$s_!5__H!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F490604c5-8c2f-4647-8f71-6237c8a45e7a_612x478.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see here, I can also use backtick commands to set flags. </p><p>I can also call parameterized commands to the engine to do stuff like play cutscenes, adjust characters, change the dialogue speed, etc. Here&#8217;s an example from the game demo:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wPwY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wPwY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 424w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 848w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 1272w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wPwY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png" width="444" height="562" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:562,&quot;width&quot;:444,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29545,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wPwY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 424w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 848w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 1272w, https://substackcdn.com/image/fetch/$s_!wPwY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b1789fa-d364-4ad6-86f8-55a91eda62e2_444x562.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>These work by calling from a predefined list of commands that interpret the parameters as an array of strings:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uYfv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uYfv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 424w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 848w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uYfv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png" width="1388" height="1024" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1388,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:188253,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uYfv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 424w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 848w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!uYfv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7958c6a0-5212-4384-808c-1536320f0ec1_1388x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Commands return a string that can be inserted in the dialogue if need be.</p><h3>Portraits</h3><p>These work using obsidian&#8217;s image links. By including a symlink to the folder in our sprites directory containing all the character portraits, we can simply link the filename, which gives us a command that changes the portrait in-game and previews it in-editor:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!EGFz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EGFz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 424w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 848w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 1272w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EGFz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png" width="431" height="363" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:363,&quot;width&quot;:431,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20298,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!EGFz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 424w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 848w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 1272w, https://substackcdn.com/image/fetch/$s_!EGFz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a7d5c04-bd11-482c-8d45-d06f3563bcd6_431x363.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Obsidian will even auto-suggest filenames:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iGId!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iGId!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 424w, https://substackcdn.com/image/fetch/$s_!iGId!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 848w, https://substackcdn.com/image/fetch/$s_!iGId!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 1272w, https://substackcdn.com/image/fetch/$s_!iGId!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iGId!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png" width="504" height="357" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:357,&quot;width&quot;:504,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27328,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iGId!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 424w, https://substackcdn.com/image/fetch/$s_!iGId!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 848w, https://substackcdn.com/image/fetch/$s_!iGId!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 1272w, https://substackcdn.com/image/fetch/$s_!iGId!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1d05ccd3-5eea-41dd-af23-9167c0afd6f1_504x357.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Maybe I should write a plugin that previews the image here too&#8230;</figcaption></figure></div><h3>Combining it All</h3><p>When put all together, these features can do some pretty nifty stuff. Take a look at this example from the game:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LHci!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LHci!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 424w, https://substackcdn.com/image/fetch/$s_!LHci!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 848w, https://substackcdn.com/image/fetch/$s_!LHci!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 1272w, https://substackcdn.com/image/fetch/$s_!LHci!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LHci!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png" width="509" height="489" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:489,&quot;width&quot;:509,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36249,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LHci!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 424w, https://substackcdn.com/image/fetch/$s_!LHci!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 848w, https://substackcdn.com/image/fetch/$s_!LHci!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 1272w, https://substackcdn.com/image/fetch/$s_!LHci!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1ca1ef91-1b2a-49fe-b108-2c0d80a10840_509x489.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>This does the following:</p><ul><li><p>It can be started by (when interacting with the relevant object in the overworld) jumping to the &#8220;repository&#8221; label in the relevant dialogue file.</p></li><li><p>Sets and unsets the dialogue portrait.</p></li><li><p>Shows a differently colored line of dialogue if certain global flags are not set.</p></li><li><p>Displays a set of choices that bring you to different parts of the dialogue. Certain choices only display if a flag is set one way or another.</p></li><li><p>Inserts a random line from another special dialogue file using the <code>repoLine</code> command.</p></li><li><p>Closes the dialogue when a choice that doesn&#8217;t jump elsewhere is selected.</p></li></ul><h3>Designed!</h3><p>And that&#8217;s how it all works in-editor!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> For most of you, <strong>I&#8217;d recommend getting off here.</strong> If you enjoyed this post, <strong><a href="https://www.kickstarter.com/projects/massimog/diorama-break/posts">check out the latest backer update to vote on the next post&#8217;s topic!</a> </strong>Oh, and also:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><p>For the rest of you who might be curious about how it all works under the hood though, let&#8217;s take a peek!</p><h1>Nitty-Gritty Boring Technical Details</h1><p>Like most systems in-engine, the dialogue system relies on a set of global variables for state. Since only one dialogue can play at any given time, a lot of the system&#8217;s state is just stored globally:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2C5c!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2C5c!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 424w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 848w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 1272w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2C5c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png" width="1456" height="1477" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1477,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:160108,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2C5c!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 424w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 848w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 1272w, https://substackcdn.com/image/fetch/$s_!2C5c!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd7e5ff9-72ff-40bc-984a-6cf45e838f87_1534x1556.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I won&#8217;t get into all the bits and bobs like HD portraits, the log, and localization, instead focusing just on how a dialogue file gets read into the engine and then interpreted at runtime.</p><h3>Loading</h3><p>First, when building the game, the dialogue build script copies all the dialogue files and places them in a flat intermediate folder for the asset packer to bundle into the final packed asset binary. It also reads all the filenames and generates an &#8220;id&#8221; code file that my Language Server can use to provide autocomplete for dialogue assets, much like the other asset build scripts. The only unique part of this script is the preprocess step, which strips out comments, trailing whitespace, unneeded heading hash symbols, and empty lines:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-ZSF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-ZSF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 424w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 848w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 1272w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-ZSF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png" width="838" height="611" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:611,&quot;width&quot;:838,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87263,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-ZSF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 424w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 848w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 1272w, https://substackcdn.com/image/fetch/$s_!-ZSF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb44f468c-d139-452f-8311-cfeeacf5c01b_838x611.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At startup, the asset loader loads the dialogue data into memory and maps it out like so: each dialogue line is its own string, stored in an array, and each dialogue also gets a map that maps each label name to an index in that array.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!orfN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!orfN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 424w, https://substackcdn.com/image/fetch/$s_!orfN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 848w, https://substackcdn.com/image/fetch/$s_!orfN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 1272w, https://substackcdn.com/image/fetch/$s_!orfN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!orfN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png" width="1456" height="271" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:271,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:40350,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!orfN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 424w, https://substackcdn.com/image/fetch/$s_!orfN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 848w, https://substackcdn.com/image/fetch/$s_!orfN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 1272w, https://substackcdn.com/image/fetch/$s_!orfN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18406c2f-6a48-431d-8a40-953cdfc6bcec_1461x272.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>&#8220;Running&#8221; a dialogue</h3><p>At almost any point, the <code>dialogue_open</code> proc can be called to open a dialogue (from the top, or at a specified label).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!G8Ec!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!G8Ec!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 424w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 848w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 1272w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!G8Ec!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png" width="1456" height="745" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:745,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:145116,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!G8Ec!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 424w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 848w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 1272w, https://substackcdn.com/image/fetch/$s_!G8Ec!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F87f28086-c111-471b-81c1-3f3e38bfef99_1508x772.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>&#8220;Blocking&#8221; here refers to if activating the dialogue should prevent the player from making other inputs for its duration.</p><p>From the open proc, I call <code>dialogue_next_line</code>. This is a monster 200-line proc and the beating heart of the interpreter. It works on the following principle:</p><ul><li><p>The dialogue system tracks its current position using a &#8220;head&#8221; (the index of the line we&#8217;re on).</p></li><li><p>Read ahead from this head in a loop until you have content that can be displayed, then stop (with a few exceptions).</p></li></ul><p>Let&#8217;s look at it step-by-step:</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!n3pJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!n3pJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 424w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 848w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 1272w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!n3pJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png" width="1456" height="283" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:283,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:49135,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!n3pJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 424w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 848w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 1272w, https://substackcdn.com/image/fetch/$s_!n3pJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34b8c854-0789-46ef-84c2-d8537b545c1e_1517x295.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>First, it:</p><ul><li><p>Ensures it&#8217;s not being called with no dialogue open.</p></li><li><p>Sets a flag that says the dialogue is currently &#8220;parsing&#8221;. This is mainly for certain label jump procedures, since they need to behave slightly differently if called from inside vs. outside the parsing loop.</p></li><li><p>Sets a &#8220;temporary head&#8221; to start reading the dialogue data.</p></li><li><p>Gets the current dialogue&#8217;s line data<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_jvi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_jvi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 424w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 848w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 1272w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_jvi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png" width="782" height="730" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/560db525-775c-481e-8cbd-30113985510e_782x730.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:730,&quot;width&quot;:782,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:82598,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_jvi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 424w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 848w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 1272w, https://substackcdn.com/image/fetch/$s_!_jvi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F560db525-775c-481e-8cbd-30113985510e_782x730.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At the top of the interpreter loop, it:</p><ul><li><p>Checks if it&#8217;s reached the end of the dialogue file, or if the exit flag was tripped, and if so closes the dialogue and stops the loop.</p></li><li><p>Checks if it&#8217;s reached the end of a &#8220;block&#8221;. These are used for conditionals and choices like we saw before, and stored on a stack. If it has reached the end of the current block, it pops it from the stack and sets the temp head to the appropriate point outside the block.</p></li><li><p>If inside one or more blocks, the block &#8220;indentations&#8221; (either tabs or quote arrows &#8216;&gt;&#8217;) are removed from the line it&#8217;s parsing.</p></li><li><p>Labels are never rendered into dialogue, so if it hits a label, it sets some flags, then skips over it.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cbNi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cbNi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 424w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 848w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cbNi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png" width="1456" height="1442" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1442,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:283856,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cbNi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 424w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 848w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 1272w, https://substackcdn.com/image/fetch/$s_!cbNi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F005e7810-e355-4c58-bfe5-f919ff970039_1507x1492.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next in the loop, it checks for choice blocks. If found, it:</p><ul><li><p>Skips over interjection choice blocks the player chose to advance past.</p></li><li><p>Begins scanning the block with another temporary &#8220;head&#8221;. The entire block is read and the information is used to determine what choices are available in the choice menu, and where the block should end.</p><ul><li><p>Some choices will be conditionally disabled, those expressions are parsed here and used to filter those choices out. Since the start of the next choice option is used to determine when the last choice&#8217;s block ends, it always adds every choice to the choice array, and disabled ones are just hidden in the menu.</p></li><li><p>Some choices are &#8220;labelled&#8221;. They will jump immediately to a label when selected, but get disabled if that label has already been seen.</p></li></ul></li><li><p>Pushes the information about the choice block to the block stack.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6F1V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6F1V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 424w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 848w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 1272w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6F1V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png" width="907" height="131" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:131,&quot;width&quot;:907,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19936,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6F1V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 424w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 848w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 1272w, https://substackcdn.com/image/fetch/$s_!6F1V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7d369c97-fc8f-4bbf-8f5d-a6ffff57ddd6_907x131.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>After that, a quick check for label jump expressions. We don&#8217;t jump right away, instead waiting for the whole line to be parsed.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fpNa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fpNa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 424w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 848w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 1272w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fpNa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png" width="1456" height="1118" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1118,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:215575,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fpNa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 424w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 848w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 1272w, https://substackcdn.com/image/fetch/$s_!fpNa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7b5080f-331c-406f-97cf-9259bd6c9263_1624x1247.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next up, conditional blocks. These are similar to choice blocks, but without a need to wait for player input to pick a branch:</p><ul><li><p>Again, the whole block is first scanned to get every conditional expression in the &#8220;if-else&#8221; chain and determine where it ends.</p></li><li><p>The conditionals are then checked in order. If any return true, the interpreter enters the block there and stops checking, otherwise the whole block is skipped over.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7vp7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7vp7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 424w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 848w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 1272w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7vp7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png" width="481" height="86" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:86,&quot;width&quot;:481,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8529,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7vp7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 424w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 848w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 1272w, https://substackcdn.com/image/fetch/$s_!7vp7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3910e023-b705-48b7-9d60-d75067fe92b2_481x86.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next up, it parses all expressions constrained to a single line. This is stuff like styling, setting portraits, calling commands, etc. We&#8217;ll get to this later.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RZkV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RZkV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 424w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 848w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 1272w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RZkV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png" width="790" height="326" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:326,&quot;width&quot;:790,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:50949,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RZkV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 424w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 848w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 1272w, https://substackcdn.com/image/fetch/$s_!RZkV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f176e8-76e7-4cbb-b13c-b610c15d2f97_790x326.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next, it jumps to any label that was set during parsing, then continues from there. Jumps must always be to somewhere outside of a block, and so the block stack can be safely cleared here.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!thHk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!thHk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 424w, https://substackcdn.com/image/fetch/$s_!thHk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 848w, https://substackcdn.com/image/fetch/$s_!thHk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 1272w, https://substackcdn.com/image/fetch/$s_!thHk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!thHk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png" width="739" height="369" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:369,&quot;width&quot;:739,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:41202,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!thHk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 424w, https://substackcdn.com/image/fetch/$s_!thHk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 848w, https://substackcdn.com/image/fetch/$s_!thHk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 1272w, https://substackcdn.com/image/fetch/$s_!thHk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb13f3e44-ca86-413f-8dda-93b4ec6bddf3_739x369.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Before the last step, it checks if the parsed line is empty. If so, it continues on interpreting until it finds content to display, unless we&#8217;re in &#8220;auto-advance&#8221; mode (i.e. when the player cannot skip or advance dialogue manually).</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LA-q!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LA-q!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 424w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 848w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 1272w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LA-q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png" width="1332" height="422" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/66419734-b844-41a3-a3da-7ff120424dca_1332x422.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:422,&quot;width&quot;:1332,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:76460,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LA-q!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 424w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 848w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 1272w, https://substackcdn.com/image/fetch/$s_!LA-q!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F66419734-b844-41a3-a3da-7ff120424dca_1332x422.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Finally, it&#8217;s ready to display the content it parsed. For the last few things, it:</p><ul><li><p>Sets the &#8220;displayed&#8221; dialogue string to the parsed line.</p></li><li><p>Dialogue uses a &#8220;typewriter count&#8221; variable to create the scrolling effect which gradually reveals the newly displayed line. If the dialogue was set to pause on the first character (&#8220;rune&#8221;) of the displayed string, sets the count to 0, which will cause the dialogue box not to be displayed for the duration of the pause.</p></li><li><p>Updates the actual dialogue head to the temporary head&#8217;s value.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V8zr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V8zr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 424w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 848w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 1272w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V8zr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png" width="1456" height="625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:625,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:113524,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V8zr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 424w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 848w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 1272w, https://substackcdn.com/image/fetch/$s_!V8zr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c133906-fcde-4da5-9aca-e1bf260ff53e_1546x664.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That would normally be the end of it, but the proc needs to do one last check. In order to display the prompt for interjection choices, it reads ahead a little to check if one exists, and constructs the menu.</p><h3>Parsing Dialogue Lines</h3><p>Rather than using the string data directly, dialogue lines get parsed into &#8220;dialogue strings&#8221;, which contain per-character metadata for styling and pauses between characters:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6t5L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6t5L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 424w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 848w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 1272w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6t5L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png" width="1200" height="254" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:254,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32791,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6t5L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 424w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 848w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 1272w, https://substackcdn.com/image/fetch/$s_!6t5L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F783d07c5-62cc-4d3c-8ebe-cd3c56b4a248_1200x254.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>The line parsing proc takes an annotated dialogue line string, and constructs a parsed DialogueString. It can be used outside the main interpreter loop with any string, making it a useful tool in general. Let&#8217;s break it down:</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wp4l!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wp4l!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 424w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 848w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 1272w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wp4l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png" width="1298" height="201" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:201,&quot;width&quot;:1298,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:51071,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wp4l!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 424w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 848w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 1272w, https://substackcdn.com/image/fetch/$s_!wp4l!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5b05ba84-e0c7-4559-a7dc-7f08cadc8e23_1298x201.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>First up, it makes the output array and clones in the input line in order to be able to mutate it. It&#8217;ll handle &#8220;non-positional&#8221; expressions, i.e. ones whose position inside the string doesn&#8217;t matter, before anything else.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!brSH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!brSH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 424w, https://substackcdn.com/image/fetch/$s_!brSH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 848w, https://substackcdn.com/image/fetch/$s_!brSH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 1272w, https://substackcdn.com/image/fetch/$s_!brSH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!brSH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png" width="1456" height="546" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:546,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:159903,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!brSH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 424w, https://substackcdn.com/image/fetch/$s_!brSH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 848w, https://substackcdn.com/image/fetch/$s_!brSH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 1272w, https://substackcdn.com/image/fetch/$s_!brSH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F85b81f82-0cb2-4d61-8ad1-0dee0b4b0878_1746x655.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>So, portrait and name tag expressions first. This simply extracts the sprite name and sets it (or sets the sprite to nothing if a blank expression is given. For name tags, the string is just extracted and set. Once these expressions are parsed, they are removed from the clone of the line that was made earlier.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jOJ0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jOJ0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 424w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 848w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 1272w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jOJ0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png" width="1456" height="310" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:310,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56773,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!jOJ0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 424w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 848w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 1272w, https://substackcdn.com/image/fetch/$s_!jOJ0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa09c3c04-8cd8-4d0a-8e4e-f446dba89ff0_1547x329.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, it gets into the positional expression loop. This goes rune-by-rune and appends them to the final parsed output. It starts by getting the rune at the current index. The first check is simply for a backslash \, which causes the parser to treat the rune after it as a literal, appending it straight-up and not doing any parsing with it.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QEVj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QEVj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 424w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 848w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 1272w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QEVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png" width="1269" height="262" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:262,&quot;width&quot;:1269,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47448,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QEVj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 424w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 848w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 1272w, https://substackcdn.com/image/fetch/$s_!QEVj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F717228a8-afb2-4c6d-909e-e49adeccb2b0_1269x262.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, since these can do anything, command parsing. These are the special custom commands we saw earlier, as well as stuff like setting flags. We&#8217;ll get to the exact way expression parsing works later.</p><p>The result of the command&#8217;s expression is inserted into the parsed line in place of the command, and the loop continues.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3P1f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3P1f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 424w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 848w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 1272w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3P1f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png" width="1380" height="934" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:934,&quot;width&quot;:1380,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:150450,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3P1f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 424w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 848w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 1272w, https://substackcdn.com/image/fetch/$s_!3P1f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ea295f6-20e9-44dd-bdfe-a9c33524920e_1380x934.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next, some simple parsing for bold, italic, and color expressions. Values are set that all runes which get added to the output from now on read from. For expressions like this that don&#8217;t insert anything into dialogue, the parser can simply move the index to skip over them before continuing the loop.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SV-A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SV-A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 424w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 848w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 1272w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SV-A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png" width="939" height="584" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:584,&quot;width&quot;:939,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:78901,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SV-A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 424w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 848w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 1272w, https://substackcdn.com/image/fetch/$s_!SV-A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fab98ddd6-46b6-4d4f-b132-82b10395e14a_939x584.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next up, cadence. To make the dialogue scroll feel more like natural speech, the parser inserts pauses at spaces after certain sets of characters like commas or periods.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aAni!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aAni!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 424w, https://substackcdn.com/image/fetch/$s_!aAni!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 848w, https://substackcdn.com/image/fetch/$s_!aAni!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 1272w, https://substackcdn.com/image/fetch/$s_!aAni!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aAni!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png" width="1404" height="166" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/228b6e1a-a276-418a-82e1-d41623788459_1404x166.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:166,&quot;width&quot;:1404,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26146,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aAni!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 424w, https://substackcdn.com/image/fetch/$s_!aAni!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 848w, https://substackcdn.com/image/fetch/$s_!aAni!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 1272w, https://substackcdn.com/image/fetch/$s_!aAni!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F228b6e1a-a276-418a-82e1-d41623788459_1404x166.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>At the end of the loop, the current rune is appended to the output string, and the index is advanced by one.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F1cJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F1cJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 424w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 848w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 1272w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F1cJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png" width="578" height="226" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98da945a-d4e9-43f7-b297-e202844c1024_578x226.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:226,&quot;width&quot;:578,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20804,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F1cJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 424w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 848w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 1272w, https://substackcdn.com/image/fetch/$s_!F1cJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98da945a-d4e9-43f7-b297-e202844c1024_578x226.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Finally, once the parsing loop is done, any trailing spaces are trimmed and the output is returned.</p><h3>Expression Parsing</h3><p>This is the most &#8220;programming language&#8221;-like aspect of the markup language, since it&#8217;s used for simple conditionals and setting variables. It might seem quite rudimentary to some; it&#8217;s handled entirely through simple recursive calls and I&#8217;m not doing anything &#8220;proper&#8221; like constructing an AST. Partly this was to save me the trouble of learning and implementing that stuff, and partly this was a deliberate design decision to keep expressions from being able to get <em>too </em>complicated. If I need to express anything much more complicated than &#8220;add one to this flag&#8221; or &#8220;check if flag x is true and flag y is not true&#8221; then I should probably be writing that code in-engine and calling a custom command.</p><p>Once again, let&#8217;s break it down:</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!zVib!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!zVib!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 424w, https://substackcdn.com/image/fetch/$s_!zVib!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 848w, https://substackcdn.com/image/fetch/$s_!zVib!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 1272w, https://substackcdn.com/image/fetch/$s_!zVib!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!zVib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png" width="1447" height="458" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:458,&quot;width&quot;:1447,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:87393,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!zVib!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 424w, https://substackcdn.com/image/fetch/$s_!zVib!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 848w, https://substackcdn.com/image/fetch/$s_!zVib!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 1272w, https://substackcdn.com/image/fetch/$s_!zVib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56a44142-52f9-4bb3-b9bf-064fcad04610_1447x458.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The parser starts by:</p><ul><li><p>Removing whitespace.</p></li><li><p>Returning early for empty expressions.</p></li><li><p>Checking whether it should tell the interpreter receiving the result to insert it into the dialogue.</p></li><li><p>Checking whether the expression is only a string literal, in which case it just returns the contents.</p></li></ul><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P30W!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P30W!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 424w, https://substackcdn.com/image/fetch/$s_!P30W!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 848w, https://substackcdn.com/image/fetch/$s_!P30W!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 1272w, https://substackcdn.com/image/fetch/$s_!P30W!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P30W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png" width="847" height="49" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:49,&quot;width&quot;:847,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10297,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!P30W!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 424w, https://substackcdn.com/image/fetch/$s_!P30W!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 848w, https://substackcdn.com/image/fetch/$s_!P30W!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 1272w, https://substackcdn.com/image/fetch/$s_!P30W!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F341d25c0-dfba-4138-b14e-c5a845d0ebd6_847x49.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, if the expression is a valid float, the parser returns it as-is.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IbKV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IbKV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 424w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 848w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 1272w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IbKV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png" width="881" height="172" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:172,&quot;width&quot;:881,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35722,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IbKV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 424w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 848w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 1272w, https://substackcdn.com/image/fetch/$s_!IbKV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F127fd9cb-f25a-42c9-b362-f50a1aedc912_881x172.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hH_O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hH_O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 424w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 848w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 1272w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hH_O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png" width="1456" height="1001" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1001,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:201689,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!hH_O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 424w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 848w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 1272w, https://substackcdn.com/image/fetch/$s_!hH_O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9181697a-078d-411a-bc21-cbaa8ed9d112_1655x1138.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next, if it&#8217;s not doing a conditional check, the parser checks for an assignment expression. If found, both operands are parsed individually, the result is calculated, and the new result is assigned.</p><p>I use my global flag system for variables here. It&#8217;s really just a map of flag names to string values, though if the parser can interpret these string values as numbers it will gladly do math with them here.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TrDr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TrDr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 424w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 848w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 1272w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TrDr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png" width="1456" height="303" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:303,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99719,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TrDr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 424w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 848w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 1272w, https://substackcdn.com/image/fetch/$s_!TrDr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc83b01d-1e4f-48a3-9039-ecac3a35865a_1556x324.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-9Jf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-9Jf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 424w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 848w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 1272w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-9Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png" width="1456" height="776" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:776,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:183596,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-9Jf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 424w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 848w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 1272w, https://substackcdn.com/image/fetch/$s_!-9Jf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f59b926-4d95-4b54-8c0f-94607f3db848_1652x881.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Similarly, after the assignments, the parser handles comparison expressions. For boolean values, it uses the strings &#8220;0&#8221; and &#8220;1&#8221;, which get converted to floating point values for comparisons like this.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ns0V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ns0V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 424w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 848w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 1272w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ns0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png" width="286" height="178" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:286,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8032,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ns0V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 424w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 848w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 1272w, https://substackcdn.com/image/fetch/$s_!Ns0V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F253f13bb-c57b-469e-a3f0-df66d3c512ec_286x178.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, if the expression starts with &#8216;!&#8217;, the parser is set to invert the final output.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!q6H2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!q6H2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 424w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 848w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 1272w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!q6H2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png" width="661" height="224" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0106d8b4-728b-4857-a427-02ea03545511_661x224.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:224,&quot;width&quot;:661,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26605,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!q6H2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 424w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 848w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 1272w, https://substackcdn.com/image/fetch/$s_!q6H2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0106d8b4-728b-4857-a427-02ea03545511_661x224.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vvgs!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vvgs!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 424w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 848w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 1272w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vvgs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png" width="1328" height="528" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:528,&quot;width&quot;:1328,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:78294,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Vvgs!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 424w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 848w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 1272w, https://substackcdn.com/image/fetch/$s_!Vvgs!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa29ada85-7c4e-49d8-88a2-b5a990077f9e_1328x528.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Next, command parsing. The command name and arguments are split by commas.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ShAM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ShAM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 424w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 848w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 1272w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ShAM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png" width="1131" height="457" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:457,&quot;width&quot;:1131,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:59101,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/196241251?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ShAM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 424w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 848w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 1272w, https://substackcdn.com/image/fetch/$s_!ShAM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F68c0b6bc-b3e9-4660-aa5c-c5f8a270de59_1131x457.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Finally, anything else. At this point, the expression should just be some arbitrary non-numeric string:</p><ul><li><p>If inside a conditional, the parser will check whether a flag with that name exists, and if so return its value. If the flag <em>doesn&#8217;t </em>exist, the expression will be treated the same as if it did and was set to false.</p></li><li><p>If <em>not </em>inside a conditional (and not trying to insert the value of a flag into dialogue), the flag with the same name as the expression will be set to true. This allows me to simply write e.g. `myExampleFlag` in order to set a flag.</p></li></ul><h1>Conclusion</h1><p>Wow! Thanks for getting through the whole thing! Once again, you can <a href="https://www.kickstarter.com/projects/massimog/diorama-break/posts">check out the latest backer update to vote on the next post&#8217;s topic!</a> See you next devlog!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>If writing their own solution, and not just using something that works out-of-the-box like RPG Maker.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>If you want to see it in action more, you can check out <a href="https://youtu.be/qawG_NKAuu4">this old demo I uploaded to my Youtube channel</a>.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>If you&#8217;re wondering about this step, it&#8217;s so I can swap in different dialogues, mainly for localization purposes.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Diorama Break is now LIVE on Kickstarter!]]></title><description><![CDATA[Click here to check it out!]]></description><link>https://blog.massimogauthier.com/p/diorama-break-is-now-live-on-kickstarter</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/diorama-break-is-now-live-on-kickstarter</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Tue, 28 Apr 2026 12:53:11 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!qBvm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://www.kickstarter.com/projects/massimog/diorama-break" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!qBvm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 424w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 848w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 1272w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!qBvm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png" width="1903" height="670" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:670,&quot;width&quot;:1903,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:680796,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:&quot;https://www.kickstarter.com/projects/massimog/diorama-break&quot;,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/195744751?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d70caa-3dd3-4269-ae7d-0ed5ad50d8f0_1903x670.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!qBvm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 424w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 848w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 1272w, https://substackcdn.com/image/fetch/$s_!qBvm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F98c2e0ed-738d-4928-8ed6-af26efa9e755_1903x670.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><strong><a href="https://www.kickstarter.com/projects/massimog/diorama-break">Click here to check it out!</a></strong></p><p>The first few days are going to be crucial. If you want to help the project succeed, here are some things you can do (besides backing, of course!) which would be a huge help to us:</p><ul><li><p><strong><a href="https://store.steampowered.com/app/4519970/Diorama_Break_Demo/?snr=1_2108_9__2107">Wishlist, follow, and leave a review</a></strong><a href="https://store.steampowered.com/app/4519970/Diorama_Break_Demo/?snr=1_2108_9__2107"> on the demo&#8217;s steam page!</a></p></li><li><p><strong><a href="https://youtu.be/jNYVRdt0850">Share</a></strong><a href="https://youtu.be/jNYVRdt0850"> the trailer with your friends!</a><br><br>Oh, and:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><p></p></li></ul><p>I&#8217;ve learned a lot in setting this campaign up and will probably put out an interesting post-mortem when all&#8217;s said and done. For now though, I have many things to attend to!</p><p>Huge thanks to everyone&#8217;s support in the last few weeks, especially <strong>hasu</strong>, who clutched up and did some great work producing most of our campaign assets.</p><p>Let&#8217;s all work together to make this project a big success!</p>]]></content:encoded></item><item><title><![CDATA[The Diorama Break Demo Soundtrack is now available for download!]]></title><description><![CDATA[Here it is!]]></description><link>https://blog.massimogauthier.com/p/the-diorama-break-demo-soundtrack</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/the-diorama-break-demo-soundtrack</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Fri, 17 Apr 2026 14:31:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/YG6xC6Rgdec" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here it is!</p><div class="bandcamp-wrap album" data-attrs="{&quot;url&quot;:&quot;https://dioramabreak.bandcamp.com/album/diorama-break-demo-ost-first-break&quot;,&quot;title&quot;:&quot;Diorama Break Demo OST -First Break-, by dante gofar&quot;,&quot;description&quot;:&quot;13 track album&quot;,&quot;thumbnail_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6dc47160-c445-46aa-9b3e-93f4600ff873_700x700.jpeg&quot;,&quot;author&quot;:&quot;Diorama Break&quot;,&quot;embed_url&quot;:&quot;https://bandcamp.com/EmbeddedPlayer/album=1485626445/size=large/bgcol=ffffff/linkcol=333333/artwork=small/transparent=true/&quot;,&quot;is_album&quot;:true}" data-component-name="BandcampToDOM"><iframe src="https://bandcamp.com/EmbeddedPlayer/album=1485626445/size=large/bgcol=ffffff/linkcol=333333/artwork=small/transparent=true/" frameborder="0" gesture="media" scrolling="no" allowfullscreen="true"></iframe></div><p>It's pay what you want, Bandcamp only lets us offer 200 free downloads per month though so if you do want to download it, get it while it's hot!</p><p>We'll also be uploading it to Youtube over the next week and a half in anticipation of the Kickstarter! Check out the first track here:</p><div id="youtube2-YG6xC6Rgdec" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;YG6xC6Rgdec&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/YG6xC6Rgdec?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Thanks again to dante (<a href="https://soundcirclet.net/">https://soundcirclet.net</a>) for mastering everything and putting it all together (and, of course, for composing all the music!) It all came out better than I ever could&#8217;ve asked for and I&#8217;m looking forward to seeing what everyone has to say about it standalone!</p>]]></content:encoded></item><item><title><![CDATA[The Diorama Break Chapter 1 Demo is Out Now on Steam!]]></title><description><![CDATA[It&#8217;s been a long month (and a half), but I&#8217;m happy to be able to say that it&#8217;s finally out of Beta and available on Steam!]]></description><link>https://blog.massimogauthier.com/p/the-diorama-break-chapter-1-demo-ddd</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/the-diorama-break-chapter-1-demo-ddd</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Tue, 07 Apr 2026 17:01:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7618049f-9e4b-4347-b021-078031f9cfc2_1920x1080.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s been a long month (and a half), but I&#8217;m happy to be able to say that it&#8217;s finally out of Beta and available on Steam! Check it out: <a href="https://store.steampowered.com/app/4519970/Diorama_Break_Demo">https://store.steampowered.com/app/4519970/Diorama_Break_Demo</a><br></p><p>If you&#8217;re still not in the loop, I&#8217;ve also got a shiny new trailer to go along with the occasion! </p><div id="youtube2-jNYVRdt0850" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;jNYVRdt0850&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/jNYVRdt0850?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><p><br>A huge thank you to everyone who played and left feedback on the beta! Many of the improvements since February would likely not have happened without you. While I&#8217;m sad I wasn&#8217;t able to get to everyone&#8217;s feedback (especially for more recent respondents), you&#8217;ve all given me a lot to think about for the full game.</p><p>While there&#8217;s still a ton that could be improved with this demo, I&#8217;ve committed to not letting the &#8220;good enough&#8221; be the enemy of the &#8220;totally shippable bro&#8221;. With that said, and even if I&#8217;ll probably still be working on this demo for weeks to come, this is nevertheless a version I&#8217;m truly proud of and ready to share far and wide.</p><p>And speaking of the full game, I can finally confirm that <strong>we&#8217;ll be launching a Kickstarter to help fund it on April 28th</strong>! If you enjoyed the demo and want to see the full project realized, keep an eye out for that and tell your friends! Really. We&#8217;re still pretty underground, so sharing the demo around is liable to have a big impact.</p><p>You can check out the pre-launch page here: <a href="https://www.kickstarter.com/projects/massimog/diorama-break">https://www.kickstarter.com/projects/massimog/diorama-break</a></p>]]></content:encoded></item><item><title><![CDATA[The Diorama Break Chapter 1 Demo is out now in OPEN BETA!]]></title><description><![CDATA[Hey everyone!]]></description><link>https://blog.massimogauthier.com/p/the-diorama-break-chapter-1-demo</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/the-diorama-break-chapter-1-demo</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Sat, 21 Feb 2026 19:33:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!WlVN!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc58c93dc-201b-41d2-b463-6960be30646a_208x208.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey everyone! Anyone who&#8217;s been following over the past year should be aware that I&#8217;ve been working on a special little Tactics JRPG. Today, I&#8217;m happy to announce that the Chapter 1 Demo for that game is now available in <strong>OPEN BETA </strong>on Itch.io: <a href="https://massimog.itch.io/dioramabreak">https://massimog.itch.io/dioramabreak</a></p><p>While this version of the demo is fully playable from start to finish, some polish, balance tweaks, and quality of life features are still forthcoming (particularly audio improvements). Once these planned changes and player feedback has been implemented, a full demo release is planned for Steam sometime in March!</p><p>Look forward to it!</p>]]></content:encoded></item><item><title><![CDATA[PAX West 2025 Retrospective]]></title><description><![CDATA[Back home after presenting Diorama Break at PAX West; the show was a big success, launching us from complete unknowns to almost 1000 wishlists on Steam!]]></description><link>https://blog.massimogauthier.com/p/pax-west-2025-retrospective</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/pax-west-2025-retrospective</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Thu, 04 Sep 2025 09:01:44 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/17ffe4f3-99c2-4789-a48e-01ed4d09b7f3_201x251.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Back home after presenting <a href="https://www.dioramabreak.com">Diorama Break</a> at PAX West; the show was a big success, launching us from complete unknowns to almost 1000 wishlists on Steam! To celebrate our new followers, I thought I&#8217;d write up a quick retrospective while the trip is still fresh in my mind, for those curious about what something like this looks like from the developer&#8217;s POV.</p><h2>The City</h2><p>I was pleasantly surprised that I was able to get to my hotel from the airport in just under an hour using Seattle&#8217;s light rail system. Coverage and frequency could be better, but the trains and stations felt pleasant and clean by North American standards. I get the sense that this system has spent what little resources it&#8217;s been given into hitting a decent standard for travelers (specifically, those staying in the city proper), which makes sense.</p><p>As is typical in NA though, things rapidly deteriorate once you get away from the city center. I went to a wrap party held at a venue about 40 minutes away, thankfully was still able to get there by train but the 15 minute walk between the station and the restaurant was along a gigantic stroad and has got to be one of the creepiest I&#8217;ve ever taken.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c0qC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c0qC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 424w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 848w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 1272w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c0qC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png" width="1456" height="1013" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1013,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8439382,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/172748437?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c0qC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 424w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 848w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 1272w, https://substackcdn.com/image/fetch/$s_!c0qC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fad8f377f-5702-4a8d-8d86-38d3bab99e51_3102x2159.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Didn&#8217;t snap a pic, but imagine walking from here to the yellow sign in the very back, at night, mostly deserted.</figcaption></figure></div><p>Google maps also lied to me about when the trains would stop running, which was fun to discover after having walked back to the station at 1AM&#8230;</p><p>The architecture was somewhat more interesting than average, though nothing breathtaking or too out of the norm for NA. Density in the city center felt like the densest parts of my home city Montreal, but over a noticeably wider area. Good, but it didn&#8217;t really blow me away like New York did. Roads were an interesting mix of very wide (three car lanes + bus lane) and quite narrow (enough to cross in two strides; I felt safe ignoring the traffic light).</p><h2>The People</h2><p>One thing I always notice visiting America is how willing total strangers on the street are to randomly say things to you or even strike up a conversation. It&#8217;s a surprising fact, since as much as people like to say Canada isn&#8217;t all that different I&#8217;ve almost never had that happen here. I&#8217;d say I&#8217;m somewhat indifferent to this over my usual status quo, it can be a fun diversion but sometimes you don&#8217;t really have the energy for it. Related to this, though this seems like more of a west coast thing: the front-facing service workers I met almost all either projected a sense that they wanted to kill me or that they are utterly <em>jazzed </em>to be talking to me<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. Both vibes are somewhat uncomfortable, but likely just because I&#8217;m used to a more &#8220;genial yet straightforward and curt&#8221; attitude.</p><p>Another thing that stood out: in discussions, I was struck by how desperate people<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> seemed to maintain social harmony, or, more accurately, a mutual sense that no one was offended or hurt by anything done or said by anyone<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. The most notable example was when mentioning to a group that I did not drink alcohol, all three people I was talking to <em>visibly </em>sprang to offer me a laundry list of reasons why that was completely fine in their eyes. When I asked them why they and others seemed to do things like that, one put forth the idea that it was due to people wanting to foster unity despite the area&#8217;s cosmopolitanism. Coming from a fairly cosmopolitan city myself, this explanation seemed lacking, though maybe it&#8217;s just a skill issue on our part. The same person claimed it was a mixed blessing though, since in his experience many would act familiar to the point where it seemed they wanted to pursue friendship, yet cancel plans and refuse to ever follow up later.</p><h2>The Food</h2><p>Was ok. The state of American takeout food always feels perfectly congruent with the litany of health crises the country is experiencing<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. I did have some nice thai food, and the hotel I was staying at had okay-ish vegan pizza next door. Tried some salty ice cream; novel, but not something I&#8217;m likely to do again. I&#8217;ll admit I did not have the time or money to try anything top rated, so don&#8217;t take this as criticism of the best Seattle has to offer.</p><h2>The Expo</h2><p>I wish I could say the actual experience of exhibiting was fun, but the build wasn&#8217;t exactly finished when we were due to start<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, so the first three days ended up very stressful and very sleepless (advice to my past self: don&#8217;t underestimate how long it will take to complete the demo by more than half, you fool, you moron<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a>). The last two days were fortunately less stressful thanks to a more stable build, but as usual for these sorts of events, marred by exhaustion. I didn&#8217;t even get to try Kirby Air Riders<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>&#8230;</p><p>We were also only two (huge, huge thanks to <a href="https://www.bezeltorpe.net/">Rowan</a>, one of the artists on the game, for flying down and helping out), which is pushing it; three feels like the minimum needed to not have someone crippled by exhaustion on the last day (again, huge, huge thanks to Rowan). Important advice: get shoes optimized for standing. I brought two pairs, my normal shoes for the trip and a pair of Hokas for the actual expo. Sit down frequently, especially if you&#8217;re in pain; don&#8217;t try to push through it. Rest properly at the end of every day.</p><p>Still, through it all, it was an incredible relief to see the very (dare I say it, overwhelmingly) positive reaction to the game. With how many unorthodox choices I made in the writing and game design, it was immensely gratifying to me to have people praise them directly, and the rest of the team were all stoked to receive so many compliments on the game&#8217;s visuals and music. And all this despite how much content was missing from the demo we showed<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-8" href="#footnote-8" target="_self">8</a>! I can&#8217;t wait to put the completed demo out and show you guys what we can really pull off.</p><p>And beyond just compliments, it&#8217;s nice to have finally created something that people cared enough about to give, uh, constructive feedback on (some of it valuable, even!). We even got recommended some games to learn from (hadn&#8217;t heard of Phantom Brigade, but I&#8217;ll definitely be <s>stealing</s> tastefully adopting some UI ideas from that game). </p><p>Everything went smoothly with the event staff and organizers, no complaints there. Though I&#8217;ll say, it must feel vaguely infantilizing for the attendees to have the enforcers form a human wall at the end of every day and sweep through the convention like a wave, bright flashing lights and all. I got the sense though that this was more a teambulding exercise for the staff rather than something deemed strictly necessary.</p><p>Also had some <a href="https://store.steampowered.com/app/2514330/The_Rabbit_Haul/">great booth neighbours</a>; was pleasant to talk to an out-of-province Canadian dev about the various things, especially the programs and services available to them, both public and private.</p><h2>Wrap-up</h2><p>With everything over and done with, it&#8217;s important to recover properly. For that and no other reason, I&#8217;ll be taking the next couple days to rest, then it&#8217;s back to the grind. Enjoy Silksong everyone!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Though in both cases, I got the distinct sense that I was someone to be Handled. Probably fair, given what these people likely have to deal with.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I don&#8217;t want to generalize too much here, this probably just applies to &#8220;Nerdy Seattleites&#8221;</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>&#8220;You&#8217;re good&#8221; seems a common response to apologies to minor mistakes. As someone used to &#8220;it&#8217;s ok/fine&#8221; this is quite notable in a way that&#8217;s difficult to put my finger on. I think it&#8217;s because the latter only communicates a fact about the world, so the former comes across as jarringly personal in comparison. </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Yet another thing that surprisingly differs so much from Quebec. I think it&#8217;s probably due to <em>much </em>more liberal use of cooking oil.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>To give you an idea, <em>all </em>of the audio was implemented in-game the night before the show.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>I blame Antonblast. I still have no idea how we (just 4 people at the time) were able to put together <em>that </em>kickstarter demo in just 4 months.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p>You guys don&#8217;t understand, he has <em>maximum pink.</em></p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-8" href="#footnote-anchor-8" class="footnote-number" contenteditable="false" target="_self">8</a><div class="footnote-content"><p>I swear, every missing interaction and UI glitch felt like a gut punch&#8230; wasn&#8217;t exactly helping my mood&#8230;</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Diorama Break Reveal]]></title><description><![CDATA[It&#8217;s finally time.]]></description><link>https://blog.massimogauthier.com/p/diorama-break-reveal</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/diorama-break-reveal</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Fri, 15 Aug 2025 21:56:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/youtube/w_728,c_limit/rGioZdM1MGY" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It&#8217;s finally time. It&#8217;s I-don&#8217;t-want-to-say-how-many months behind schedule, but I&#8217;m finally ready to show a peek of what I&#8217;ve been working on since Antonblast came out:</p><div id="youtube2-rGioZdM1MGY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;rGioZdM1MGY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/rGioZdM1MGY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Waow! Wondering where this will go? Maybe, uuuuuuuuh&#8230; subscribe? </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><p>Me and my team are working as fast as we can to finish up a proper demo within the next couple months (as the ship that is my personal funds buckles and collapses beneath us); I&#8217;ll definitely have more to share here then (or earlier, if I feel like it). And as the project progresses, I&#8217;ll aim to post regular updates about whatever it is we&#8217;ve been working on lately, if it turns out there&#8217;s an audience for it.</p><p>In the meantime though, why not join the new <a href="https://discord.gg/4gVZXqVHmA">discord</a> or <a href="https://store.steampowered.com/app/3932580/Diorama_Break">wishlist the game on steam</a>? Who knows, maybe you&#8217;ll find some more info about the project there&#8230;</p><p>If you just can&#8217;t wait to play it though, we&#8217;re planning to have the first half of the planned demo playable at PAX West in just under a month! <a href="https://west.paxsite.com/en-us/expo-hall/arch-expo-hall/showroom.html?gtID=628821&amp;exhibitor-name=Studio-Massimo-Gauthier-inc">Come check us out in the Arch Expo Hall</a>.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Seeing how well an agentic AI coding tool can do compared to me using an actual real-world example]]></title><description><![CDATA[As you may or may not know, I am in the camp of those concerned about existential risk from AI (don&#8217;t know what that is?]]></description><link>https://blog.massimogauthier.com/p/seeing-how-well-an-agentic-ai-coding</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/seeing-how-well-an-agentic-ai-coding</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Sun, 01 Jun 2025 16:39:29 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!BY6f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As you may or may not know, I am in the camp of those concerned about existential risk from AI (don&#8217;t know what that is? There are plenty of good explainers out there, from the more <a href="https://youtu.be/0bnxF9YfyFI?si=jnWlbnFeAVVsOvat">accessible</a> to the more <a href="https://www.lesswrong.com/posts/uMQ3cqWDPHhjtiesc/agi-ruin-a-list-of-lethalities">advanced</a>). As part of that ongoing interest in not seeing me and everything I love melted down for raw materials, I try keep up with developments in AI capabilities. Recently, though it has little to do with <em>that </em>giant world-ending problem, I stumbled across a more mundane dispute that overlaps with my other interests: </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BY6f!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BY6f!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 424w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 848w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 1272w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BY6f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png" width="887" height="494" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:494,&quot;width&quot;:887,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!BY6f!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 424w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 848w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 1272w, https://substackcdn.com/image/fetch/$s_!BY6f!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d97181b-4a76-43cc-9b7d-a59bee8105f2_887x494.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rEuF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rEuF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 424w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 848w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 1272w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rEuF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png" width="905" height="459" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:459,&quot;width&quot;:905,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83077,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F684b7c85-f891-4c8e-af9c-7fbc2ce818ba_905x462.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rEuF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 424w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 848w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 1272w, https://substackcdn.com/image/fetch/$s_!rEuF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8ceb7026-d0bf-404e-b12f-d49db1b08204_905x459.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In a sense, I think this Stokes guy is right. Capabilities are improving at tremendous speed, anyone like me expecting AI to get to the point where it can conquer the world (or, more optimistically, all jobs) should naturally expect to see it master software development sometime before then. But the point of contention <em>here </em>is whether current AI systems can even provide significant productivity gains to programmers working on meaningful, complex systems and&#8230; ha&#8230; haha&#8230; yeah, I&#8217;m very much on Blow&#8217;s side on that one.</p><p>But, y&#8217;know, anyone can just toss that opinion out there. Fortunately for me though, it doesn&#8217;t seem like many skilled programmers that hold the &#8220;current AI is incompetent&#8221; view have actually bothered to substantiate their point (at least, with an article like this). I feel like, when I see these sorts of disputes, a lot of people are missing context.<em>Everyone </em>agrees the AI isn&#8217;t perfect, but what exactly is the AI failing at and why does it seem to matter so much more to some people? As someone who has tried AI out in multiple contexts, I thought it would be valuable to give the &#8220;strongest&#8221; tools a fair shot and closely scrutinize and critique the actual outputs. Who knows, maybe I&#8217;ll get a benchmark named after me<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>.</p><h1>The Task</h1><p>The task is simple, and so are the rules:</p><ul><li><p>I have recently added a simple camera shake feature to the game I&#8217;m working on. This was done without any AI assistance. Based on the edit history of the relevant files, this took me about 30 minutes.</p></li><li><p>I will branch off from just before I added the feature, then use an AI tool to recreate it. My goal will not be to necessarily perfectly replicate my implementation, but to prompt the AI and make edits until it&#8217;s version of the feature is basically functional. I will then critique the code it provided throughout this process.</p></li><li><p>If the AI tool and I cannot achieve basic functionality (from when I start typing the first prompt for the AI), I will critique what work it <em>was </em>able to do inside of 30 minutes.</p></li></ul><p>Frankly, I&#8217;m throwing the AI a bit of a softball here. The problem is not too difficult, we&#8217;re not doing any major overhauls to the program&#8217;s structure, we&#8217;re not adding a feature that touches multiple systems, and most of the structure is already in place, no need to add any entirely new systems. This is partly to keep this test easy to run, partly to keep things short and understandable for beginners, and partly as an additional sneaky test for the AI: can it recognize that there&#8217;s no need to overcomplicate things?</p><h2>My implementation</h2><p>Before we give the AI a shot, let&#8217;s take a look at my existing implementation to get an idea of where our standards are at.</p><p>As mentioned, the goal was to create a camera shake system. Specifically, I wanted a function I could call which:</p><ul><li><p>Takes a duration (in frames) and a force (in pixels) and shakes the camera that much, for that long.</p></li><li><p>Calling the function multiple times should create an <em>additive </em>effect, so multiple sources of camera shake can add up to create a stronger overall effect.</p></li><li><p>I&#8217;d also like the ability to limit the shake to only the x or y axis.</p></li></ul><p>Before I started, the camera was mainly controlled by the stage system, and its final position primarily depended on three global vector2 variables:</p><ul><li><p><strong>stage.target_camera_pos</strong>: Primarily meant to be messed around with by entities in the stage. After setting this value, the camera&#8217;s <em>center position </em>will (later in the frame, when the camera updates) be moved to this value. At the moment, the camera will always snap instantly to this position, but in the future I may have it move more smoothly/gradually towards it.</p></li><li><p><strong>stage.camera_pos</strong>:<strong> </strong>The camera&#8217;s actual position in the stage. If you imagine the camera&#8217;s view as a rectangle, this position would be in the top left.</p></li><li><p><strong>camera.pos</strong>:<strong> </strong>When the game draws anything, this value is applied such that the camera system works as intended. This value is extremely volatile and is mainly intended to be a cached value that can be quickly accessed and used in drawing functions without needing to cast or modify the value. When changing drawing contexts (such as when drawing to a separate texture), a new camera position is pushed onto a stack, and is popped off said stack when returning to the previous drawing context. Whenever the stack changes, this value is updated to reflect the top value of the stack. Also corresponds to the camera&#8217;s top-left position. <strong>stage.camera_pos</strong> gets pushed onto the base of the stack when the current stage begins rendering. </p></li></ul><p>Here&#8217;s what the stage system update (which was basically just camera code) looked like:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!htCe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!htCe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 424w, https://substackcdn.com/image/fetch/$s_!htCe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 848w, https://substackcdn.com/image/fetch/$s_!htCe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 1272w, https://substackcdn.com/image/fetch/$s_!htCe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!htCe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png" width="1409" height="332" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:332,&quot;width&quot;:1409,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:70231,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!htCe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 424w, https://substackcdn.com/image/fetch/$s_!htCe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 848w, https://substackcdn.com/image/fetch/$s_!htCe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 1272w, https://substackcdn.com/image/fetch/$s_!htCe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10321551-d0dc-4de6-a09e-b6b8902e977a_1409x332.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>In summary:</p><ul><li><p>If the camera is tracking a specific entity, set the target position accordingly.</p></li><li><p>Set stage.camera_pos based on stage.target_camera_pos</p></li><li><p>Clamp stage.camera_pos to the stage bounds.</p></li></ul><p>camera.pos is then set via the provided function in the stage rendering code, right before it starts drawing stuff:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8-2x!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8-2x!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 424w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 848w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 1272w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8-2x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png" width="909" height="263" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:263,&quot;width&quot;:909,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38950,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8-2x!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 424w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 848w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 1272w, https://substackcdn.com/image/fetch/$s_!8-2x!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F94f3b3dc-9790-4d8f-8398-5cb0f2ed2111_909x263.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p>Alright, with all that preamble out of the way, let&#8217;s look at the changes made. Since I was finally adding per-frame camera-related behavior that arguably wasn&#8217;t also closely tied to the stage system, I first decided to move all the camera code in the stage system to a camera-specific update function:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k4hF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k4hF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 424w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 848w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 1272w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k4hF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png" width="1456" height="267" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:267,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30899,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k4hF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 424w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 848w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 1272w, https://substackcdn.com/image/fetch/$s_!k4hF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff5e26094-1c75-4ab3-932e-8e3a4f5b02ee_1645x302.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NIpp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NIpp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 424w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 848w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 1272w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NIpp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png" width="1456" height="225" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:225,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!NIpp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 424w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 848w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 1272w, https://substackcdn.com/image/fetch/$s_!NIpp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F070fadd0-3b15-42fc-950b-2a8451a8866a_1713x265.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!x1LE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!x1LE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 424w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 848w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 1272w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!x1LE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png" width="557" height="333" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:333,&quot;width&quot;:557,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22598,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!x1LE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 424w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 848w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 1272w, https://substackcdn.com/image/fetch/$s_!x1LE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F58c410ff-5820-48e6-8565-e87f2c6c4403_557x333.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That left _stage_system_update empty, but I decided to keep it around in case I want to add anything non-camera related to it later. </p><p>The simplest form of camera shake essentially just involves adding some random value to the camera&#8217;s &#8220;unshaken&#8221; position every frame. With that in mind, and since _camera_system_update is intended to be the &#8220;end point&#8221; for any camera changes in a frame (i.e. any special camera behaviors I add in the future will either be called inside the function or before it), I decided to implement camera shake by modifying stage.camera_pos after we&#8217;ve set it in _camera_system_update. Since I wanted the camera to be able to shake slightly outside the room bounds, I decided to add the shaking code <em>after </em>we clamp stage.camera_pos.</p><p>But I still needed some values to refer to in order to determine how much shaking to apply. Since we want shaking to be able come from different sources, which could shake things for different lengths of time and with different strength, I decided the best way to proceed was to have a pool of shake &#8220;requests&#8221; that can be added to or removed from<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aRk2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aRk2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 424w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 848w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 1272w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aRk2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png" width="915" height="743" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:743,&quot;width&quot;:915,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55326,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aRk2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 424w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 848w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 1272w, https://substackcdn.com/image/fetch/$s_!aRk2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F202966b8-9cc0-43e4-b50a-8a7277ede8ac_915x743.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Each shake request stores a how long it should keep on going for, as well as a force value. The force is stored as a vector2, allowing me to apply different amounts to the x and y axis.</p><p>Exposing this to the &#8220;user&#8221; (me) in the form of the originally specified function is trivial:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N_JG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N_JG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 424w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 848w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 1272w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N_JG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png" width="638" height="191" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8f27885-0b32-490f-8679-d57891e05c18_638x191.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:191,&quot;width&quot;:638,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:21755,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!N_JG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 424w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 848w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 1272w, https://substackcdn.com/image/fetch/$s_!N_JG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8f27885-0b32-490f-8679-d57891e05c18_638x191.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>With all that out of the way, applying the actual shake is simple:</p><ul><li><p>Loop through all the requests, adding up their force, updating their timers and removing them when they run out. The order of the requests doesn&#8217;t matter, so we can use an O(1) time unordered remove.</p></li><li><p>Once you have the total force, for both the x and y axis:</p><ul><li><p>Clamp the force to avoid edge cases where its unnoticeable or overwhelming</p></li><li><p>Apply some randomness to make the camera shake feel more varied</p></li><li><p>Add or subtract (at random) the force value to the camera position </p></li></ul></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oUaF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oUaF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 424w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 848w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 1272w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oUaF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png" width="792" height="601" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b7001212-eb9e-40ad-9210-49eb529385b9_792x601.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:601,&quot;width&quot;:792,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:93450,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oUaF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 424w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 848w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 1272w, https://substackcdn.com/image/fetch/$s_!oUaF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb7001212-eb9e-40ad-9210-49eb529385b9_792x601.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And voila! Now all that was left to do was test and see if it works. The easiest thing to do was just to throw something at the top of the player&#8217;s update loop, so that&#8217;s what I did:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tn1k!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tn1k!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 424w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 848w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 1272w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tn1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png" width="450" height="117" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:117,&quot;width&quot;:450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:20493,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!tn1k!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 424w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 848w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 1272w, https://substackcdn.com/image/fetch/$s_!tn1k!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ad2d412-3aaf-410e-8683-cfa70331aeae_450x117.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cj5J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cj5J!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cj5J!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:10558168,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!cj5J!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!cj5J!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0bb355ed-1593-4d60-96ed-546ad7e93edb_1920x1080.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Waow!</p><p>Here are some combined calls. With this code, the camera shake should increase significantly for 10 frames (1/6th of a second) whenever I click (I also made Pro flinch for effect):</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UTsC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UTsC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 424w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 848w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 1272w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UTsC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png" width="1170" height="235" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:235,&quot;width&quot;:1170,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57718,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UTsC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 424w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 848w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 1272w, https://substackcdn.com/image/fetch/$s_!UTsC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae5baef-7ca6-4c63-9eb5-63809a3f34c5_1170x235.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wIOb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wIOb!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wIOb!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:null,&quot;width&quot;:null,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13244359,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wIOb!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!wIOb!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff674b221-7f5f-408b-9536-d33f50895e27_1920x1080.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here&#8217;s vertical shake only:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sQUo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sQUo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 424w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 848w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 1272w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sQUo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png" width="1175" height="195" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:195,&quot;width&quot;:1175,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52583,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!sQUo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 424w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 848w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 1272w, https://substackcdn.com/image/fetch/$s_!sQUo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4098b0a9-5ad2-49b1-a87a-7cf585d02809_1175x195.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Vf5e!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Vf5e!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Vf5e!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:819,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:8145933,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Vf5e!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 424w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 848w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 1272w, https://substackcdn.com/image/fetch/$s_!Vf5e!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f2f58cc-30ee-4b93-bad3-518f53232d03_1920x1080.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Tubular!</p><p>And all in just about 30 changed lines!</p><p>Now let&#8217;s see how the AI handles it.</p><h2>The AI&#8217;s implementation</h2><p><em>While I have tried Claude Code in the past, for maximum fairness, I wrote the previous sections before running this test, and won&#8217;t be making any major edits to them after conducting the test.</em></p><p>You&#8217;ve been able to ask AI chatbots to spit out code for you for quite a while now, but more recently firms have begun offering &#8220;agentic&#8221; AI coding tools which can take a look at entire codebases and intelligently make changes. I&#8217;m not interested in comparing a bunch of different tools, so let&#8217;s just go with the best, which right now is&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mCfX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mCfX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 424w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 848w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 1272w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mCfX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png" width="1000" height="923" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:923,&quot;width&quot;:1000,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:90130,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mCfX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 424w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 848w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 1272w, https://substackcdn.com/image/fetch/$s_!mCfX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e50ba2a-4e41-4931-a42f-66efeb6f3012_1000x923.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://www.vellum.ai/llm-leaderboard">https://www.vellum.ai/llm-leaderboard</a></figcaption></figure></div><p><a href="https://www.anthropic.com/claude-code">Claude Code</a>!</p><p>Setting things up wasn&#8217;t too tough, now let&#8217;s jump right in. You&#8217;ve already seen the initial prompt earlier:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j7Zc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j7Zc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 424w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 848w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 1272w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j7Zc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png" width="1270" height="405" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:405,&quot;width&quot;:1270,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38278,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!j7Zc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 424w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 848w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 1272w, https://substackcdn.com/image/fetch/$s_!j7Zc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa0d4bb45-e93f-452d-8f3c-eaca7c1d1b74_1270x405.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And here&#8217;s the first edit it came up with:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Tq_B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Tq_B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 424w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 848w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 1272w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Tq_B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png" width="502" height="551" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:551,&quot;width&quot;:502,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34937,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Tq_B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 424w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 848w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 1272w, https://substackcdn.com/image/fetch/$s_!Tq_B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34ce7585-91c4-4d71-a41e-ad1b6f2d89ef_502x551.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Impressive! The core idea is there, with only a little overcomplication compared to my implementation. Let&#8217;s see if we can correct that:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XUSD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XUSD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 424w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 848w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 1272w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XUSD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png" width="1456" height="481" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:481,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63094,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XUSD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 424w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 848w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 1272w, https://substackcdn.com/image/fetch/$s_!XUSD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3273fbd3-6946-4717-a2a8-1cc9d3b7b5ed_1829x604.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Nice.</p><p>It also remembers to init the data structure:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_2Xz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_2Xz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 424w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 848w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 1272w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_2Xz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png" width="457" height="295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:295,&quot;width&quot;:457,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16932,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_2Xz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 424w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 848w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 1272w, https://substackcdn.com/image/fetch/$s_!_2Xz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F066de70d-43b0-4dc9-8791-51dc2f6e36df_457x295.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here&#8217;s the main implementation:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0B0A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0B0A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 424w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 848w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 1272w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0B0A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png" width="738" height="960" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:960,&quot;width&quot;:738,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:79055,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0B0A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 424w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 848w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 1272w, https://substackcdn.com/image/fetch/$s_!0B0A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9ffc31fd-f12f-4e78-9d57-2673ca5a7ea8_738x960.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Not bad. Here are the issues though:</p><ul><li><p>The extra camera_shake functions are a nice touch, but given that Odin makes it easy to provide a Vec2 <em>or </em>a scalar to camera_shake, ultimately unnecessary.</p></li><li><p>It&#8217;s keeping a separate global variable for the shake offset. I didn&#8217;t catch that earlier; as you know, it&#8217;s unnecessary.</p></li><li><p>It doesn&#8217;t bother using odin&#8217;s special loop syntax, making the loop definition a teensy bit harder to parse than it needs to be.</p></li><li><p>It uses an ordered_remove to get rid of expired &#8220;shake instances&#8221;, wasting time unnecessarily. Surprising, since it&#8217;s still looping through the instances in reverse.</p></li><li><p>It correctly applies a bit of randomness to the shake, but this is done in an overly wordy way. It also gets the random function&#8217;s name wrong (should be random_f). The exact way randomness is applied is also not quite the same as what I&#8217;m doing, but that&#8217;s not super important and it does result in less calls to the RNG for now. Since this is something I plan to refine later even in my own implementation, I&#8217;ll leave it like this for now.</p></li><li><p>It doesn&#8217;t clamp the shake, but given that I never asked it to do this I&#8217;ll give it a pass for now and come back to that later.</p></li></ul><p>Let&#8217;s give it feedback on the major problems and see where it goes with it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dCF5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dCF5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 424w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 848w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 1272w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dCF5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png" width="1293" height="919" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:919,&quot;width&quot;:1293,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91699,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dCF5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 424w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 848w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 1272w, https://substackcdn.com/image/fetch/$s_!dCF5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5bd37550-0940-4b09-ae76-8fa8389d5ce2_1293x919.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Still a bit more verbose than I&#8217;d like, but let&#8217;s move on.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TRpK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TRpK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 424w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 848w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 1272w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TRpK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png" width="778" height="450" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/91e75468-c443-4015-9949-4826815039ca_778x450.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:778,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:38305,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TRpK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 424w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 848w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 1272w, https://substackcdn.com/image/fetch/$s_!TRpK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91e75468-c443-4015-9949-4826815039ca_778x450.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Its plan is revealed! This comes before the clamp though, so let&#8217;s fix that, as well as the unnecessary global while we&#8217;re at it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!exfx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!exfx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 424w, https://substackcdn.com/image/fetch/$s_!exfx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 848w, https://substackcdn.com/image/fetch/$s_!exfx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 1272w, https://substackcdn.com/image/fetch/$s_!exfx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!exfx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png" width="1456" height="1016" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1016,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:211874,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!exfx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 424w, https://substackcdn.com/image/fetch/$s_!exfx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 848w, https://substackcdn.com/image/fetch/$s_!exfx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 1272w, https://substackcdn.com/image/fetch/$s_!exfx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fae12dbe4-c119-4694-8356-48584a9bdec9_2297x1603.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Cool.</p><p>It then tries to see if the code compiles, but I tell it that I have my own build pipeline and it should just add some test code and let me run it:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2xJe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2xJe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 424w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 848w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 1272w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2xJe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png" width="913" height="383" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:383,&quot;width&quot;:913,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:34979,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2xJe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 424w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 848w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 1272w, https://substackcdn.com/image/fetch/$s_!2xJe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5cd5e57-3c8c-4423-9f77-03b8ef8dfadd_913x383.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Good enough. Testing in-game, it all builds and works fine (Claude has a strange idea of &#8220;gentle&#8221;, but whatever).</p><p>Oh, let&#8217;s not forget:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0epg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0epg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 424w, https://substackcdn.com/image/fetch/$s_!0epg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 848w, https://substackcdn.com/image/fetch/$s_!0epg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 1272w, https://substackcdn.com/image/fetch/$s_!0epg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0epg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png" width="1380" height="809" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:809,&quot;width&quot;:1380,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:81879,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://blog.massimogauthier.com/i/164847546?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0epg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 424w, https://substackcdn.com/image/fetch/$s_!0epg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 848w, https://substackcdn.com/image/fetch/$s_!0epg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 1272w, https://substackcdn.com/image/fetch/$s_!0epg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc20993e7-399b-49b0-a39b-fe9ed7b83189_1380x809.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Wow, that&#8217;s a bit much. Whatever though, also good enough.</p><h1>How&#8217;d it do?</h1><p>Frankly, pretty good! Claude was definitely off the mark at times, but with some scrutiny and feedback, it managed to get pretty close to our &#8220;ideal&#8221; implementation. Sure, its syntax is a little more verbose than necessary, and its architecture is a little less clean (still pretty well segmented though, nothing I&#8217;d consider egregiously wrong). Still, verbosity is a real cost, Claude sometimes taking a dozen lines to express what I can cleanly express in 1-2 can add up to serious problems in terms of readability and maintainability. I can always go clean it up, but man, that&#8217;s gonna add more time, let&#8217;s check and see how long Claude and I were at it-</p><p>Oh. 50 minutes, huh? So much for 5x productivity gains&#8230;</p><p>In the end, I think this test isn&#8217;t going to satisfy either side of the debate very much. Those who believe in the current power of the tools are gonna feel like I spent too long studying and nitpicking every last detail of the AI&#8217;s implementation, squandering any productivity gains. The skeptics, on the other hand, will likely see this task as trivial, and not really proving anything about serious capabilities<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>. I think a more serious version of this would involve running the same process on the implementation of a large and complex system that took multiple days to complete and touched many different parts of the codebase (and didn&#8217;t have as straightforward of an implementation strategy). But that would be far more difficult to fit into a short, accessible post like this one, and I have better things to do<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>!!</p><p>Still, for any confused onlookers willing to really study the details shown here (I do it all for you, my lovelies), I think this exercise will offer you some insight into the current power of these tools. At least until the next big capabilities leap in 6 months completely obsoletes this post.</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to receive my new posts via email.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Or more likely just get a bunch of people yelling at me that I&#8217;m not using the AI right.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Since this is a dynamic memory structure, it needs to be initialized alongside the camera system. It exists for the lifetime of the program and we never need to worry about freeing it though, so we can just use the default allocator. &#8220;init&#8221; here is just a proc group I made for initializing data structures in general, it contains a proc that simply calls the built-in make_dynamic_array.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>And also, the fact I had already completed the task myself and knew exactly what to ask for is certainly giving the model a leg-up.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>But maybe I&#8217;ll do a part 2 the next time I use AI to help me build something from scratch. </p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Finale]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-ceb</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-ceb</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Wed, 29 Jan 2025 07:00:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/48314c0b-7002-4b16-9d8f-41ee4526836b_1272x1131.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d">&lt;Previous post</a></em></p><div><hr></div><p>Oof, been a while hasn&#8217;t it? It&#8217;s January now and I wrote the previous two posts I just uploaded alongside this one back in August, didn&#8217;t quite have time to put the finishing touches on them before work on Antonblast went crazy, so they languished in my drafts for a bit. Oh yeah, Antonblast, that <a href="https://store.steampowered.com/app/1887400/ANTONBLAST/">came out</a>! I&#8217;d be surprised of anyone reading this hasn&#8217;t seen it already, but in case you didn&#8217;t read the first post in this series, my frustrations working in Game Maker on that project was what set me down this path of making my own engine in the first place. And my opinion hasn&#8217;t exactly turned around, getting that game ready for a Switch release was a nightmare all on its own (one I might write a bit about in a future post). But anyway, it&#8217;s time to put an end to this series, because guess what?</p><p>I did it!! Woo!!!</p><p>That&#8217;s right! As of&#8230; uh&#8230; roughly September-ish, I finally completed my engine! And just in time too, &#8216;cause its first game has officially been in full development since December, just as planned! That&#8217;s been a real timesink, lemme tell ya, but I felt bad not having finished this series, so before my life is <em>entirely </em>consumed by that project, I&#8217;ll run through all the little stuff I missed:</p><h1>Fonts and text rendering</h1><p>Frankly, there&#8217;s a lot more to this topic than I could write about in 100 posts or that I even know, so I&#8217;ll just cover how I handled things for my own purposes. </p><p>When building a text rendering system, you might be tempted, as I was, to just load font (.ttf) files alongside your other assets, then use a library like SDL ttf to read those files and render out your fonts whenever you need to draw text. This was unfortunately a misstep that cost me a few days to fix, because doing things this way is <em>slow. </em>Every time I wanted to draw a new character at a given size, the library would have to generate a texture for that single character using the .ttf file data, which I had to send to the GPU whenever I wanted to draw that single character (see the post on sprites to learn why this isn&#8217;t great). While most libraries will do some caching to help alleviate this, it will still cause unacceptable lag spikes that one doesn&#8217;t have a ton of control over (one frame in testing that had to draw a paragraph of text for the first time all at once took <em>40 whole milliseconds</em> to render, disgusting).</p><p>So, what&#8217;s the alternative? While there are definitely ways to make using .ttf files at runtime faster, if you know ahead of time what fonts you&#8217;ll need and what size you&#8217;ll need them at, it&#8217;s better to just cut out the middle man and pre-generate some font texture pages! Just like sprite texture pages, these are large images that have all the characters of a font rendered onto them and packed tightly together, along with an index file that records where each individual character is located in that image. Rather than including the .ttf file in the final game assets, the build process simply reads those .ttf files, generates these pages, only includes <em>them </em>in the actual game. When rendering text, I can then copy the image data from these textures, and just like sprite pages these have the advantage of being able to batch multiple character draws together before having to send new data to the GPU.</p><p>In order to make this process possible, each .ttf font should have some kind of attached config data that specifies how it gets converted to a font page (I use little .json files stored in the same folder). This data should look something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bAa0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bAa0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 424w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 848w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 1272w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bAa0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png" width="512" height="174" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:174,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11063,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bAa0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 424w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 848w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 1272w, https://substackcdn.com/image/fetch/$s_!bAa0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1954b010-2871-41e0-be70-5b7c93a05e41_512x174.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><ul><li><p><strong>Ranges: </strong>Specifies which characters I want to actually have on the font page using <a href="https://jrgraphix.net/research/unicode_blocks.php">unicode ranges</a>. Most games won&#8217;t really need to display e.g. <a href="https://jrgraphix.net/r/Unicode/10380-1039F">the ugaritic alphabet</a>, so it&#8217;s useful to be able to narrow down the characters I need, to save on texture space. The ranges in the example above correspond to the Japanese <a href="https://jrgraphix.net/r/Unicode/3040-309F">hiragana</a> and <a href="https://jrgraphix.net/r/Unicode/30A0-30FF">katakana </a>syllabaries (I&#8217;ve made it so my system always exports the basic latin characters no matter what). If you&#8217;re confused as to why the numbers at the links don&#8217;t match what&#8217;s written in the example, that&#8217;s because unicode indices (&#8216;code points&#8217;) are usually written in <a href="https://simple.wikipedia.org/wiki/Hexadecimal">hexadecimal</a>. If you convert the numbers into decimal, you&#8217;ll see that they match up with the ones I&#8217;ve written.</p></li><li><p><strong>Sizes: </strong>What sizes of the font I want to export. Since I can&#8217;t read the .ttf file on the fly, the texture data I&#8217;m rendering in-game is static, unchanging, so each different size needs to be pre-rendered separately.</p></li><li><p><strong>Page: </strong>Which page to put the font data on. If multiple fonts are often used together, they can be packed together on the same page to make rendering them more efficient.</p></li></ul><h1>Collision</h1><p>This is more of a per-game thing, but I&#8217;ll cover a quick solution for collision that can work in a lot of situations.</p><p>The basic operation of a collision system is checking whether two shapes are overlapping. In the simplest case, two rectangles (call them A and B), this is done by checking 4 things:</p><ul><li><p>If the x position of the left edge of A less than (i.e. to the left of) the x position of the right edge of B</p></li><li><p>If the x position of the right edge of A more than the x position of the left edge of B</p></li><li><p>If the y position of the top edge of A is less than (i.e. above) the bottom edge of B</p></li><li><p>If the y position of the bottom edge of A is more than the y position of the top edge of B</p></li></ul><p>If all 4 of these things are true, it means the rectangles are overlapping (think about it carefully). </p><p>While checking this can be quick, often things get dicey once there are a lot of rectangles to check. Say I&#8217;m a rectangle (maybe I&#8217;m attached to a player) in a stage with 100 other rectangles (maybe they&#8217;re attached to walls, or enemies). To know if I&#8217;m overlapping with any of them, I need to check those 4 conditions 100 times! And I might need to do that several times in one frame (for example, if I&#8217;m moving, say, 8 pixels this frame, then every pixel I move I need to check all 100 rectangles again to know if I&#8217;ve hit a wall and need to stop. In the worst case, that&#8217;s 800 checks). And if any of the <em>other </em>rectangles want to do similar collision checking, they have to go through all the others too! 100 rectangles that want to collide with each other means 10000 collision checks!</p><p>Ok, calling them &#8216;rectangles&#8217; is a bit weird, they&#8217;re usually called &#8216;colliders&#8217;, since they don&#8217;t necessarily have to be rectangles, so I&#8217;ll switch to that, but keep in mind that no matter what we&#8217;re just checking if two shapes overlap.</p><p>Anyway, there are several paths to optimization here, but a simple and easy one is to just narrow down the number of colliders we need to check. If a tiny collider is on one end of a large stage, I know for sure it&#8217;s not going to be colliding with another tiny collider all the way on the other end. Knowing this, I can split the stage up into &#8220;partitions&#8221;, which each has a list of the colliders it contains<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. Whenever a rectangle is created or moved, I check if it moved out of a partition or into a new one and register or deregister it with that partition. Then, when doing collision checks with a rectangle, I first check which partitions that collider overlaps, and then only check for collisions with colliders registered to those partitions. If done properly, this cuts down massively on the number of collision checks that need to be done in one frame, great success!</p><p>So what about non-rectangle shapes? Different pairs of common shapes will have different &#8220;fast&#8221; ways of checking overlap, but rectangles are basically always fastest to check, so usually colliders will keep track of their shape as well as a &#8216;bounding box&#8217;, i.e. a rectangle that perfectly encloses the shape. Since most things aren&#8217;t overlapping most of the time, when checking for overlap between one or more non-rectangles, overlap between bounding boxes will be checked <em>first</em>, then the more expensive check will be done if and only if the bounding boxes overlap (since we can infer that the enclosed shapes aren&#8217;t overlapping if their bounds aren&#8217;t). This saves on doing a bunch of expensive checks. But what <em>are </em>those checks?? To be honest, for my purposes rectangles work 90% of the time, so I didn&#8217;t bother implementing any other common shapes. The other 10% is covered by &#8220;precise&#8221; collisions, i.e. irregular shapes, usually ones that conform to the exact shape of a sprite. To check these, I basically brute force it: for every &#8220;solid&#8221; pixel in shape A, I check if its position matches any solid pixel in shape B. This can be quite expensive, but it will happily handle any weird shape you can draw to a grid, and these sorts of collisions are so rare that it&#8217;s not usually a big deal. And if it ever does get to be a problem in a specific case, I can always just devise a more optimal solution for that specific case.</p><h1>Shaders</h1><p>Ugh, another topic that people can and have written whole textbooks about. Frankly, I&#8217;m not an expert on this, but basically the GPU&#8217;s shader is the program it runs which determines how it actually renders out texture data. Custom shaders can be used to produce all sorts of creative visual effects (as well as leverage the GPUs parallelism to do certain kinds of computations), but they&#8217;re always written in their own quirky languages due to said parallelism, and are limited in their ability to communicate with your main program.</p><p>Initially, these gave me a bit of trouble, since SDL2&#8217;s basic rendering backend, which handles making a lot of the more complicated calls to a graphics library such as OpenGL (which is what is ultimately making the CPU talk to the GPU), did not support shaders out of the box. Since I didn&#8217;t have the time to properly learn OpenGL and outright replace SDL&#8217;s functionality here I was in a bit of a bind. However, I figured out, through a lot of stressful research and trial-and-error, that by forcing SDL to use OpenGL as the rendering backend for its basic renderer you can make some simple calls to OpenGL to set a custom shader before calling SDL&#8217;s rendering functions, and the shader will work correctly. <em>Nowhere on the internet </em>is this explained explicitly, so, uh, you heard it here first folks!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a></p><p>Anyway, once all that was figured out, the rest was just a question of writing some shaders and adding them to the asset system. The sorts of shaders I want to use are few and fairly short, so I can get away with just packing the shader code (i.e. the text of the program, written OpenGL&#8217;s shader language, GLSL) in with the rest of my assets, then calling OpenGL when the game starts to compile that code into usable instructions that can be passed on to the GPU when needed.</p><p>Again, really not an expert here, I couldn&#8217;t yet tell you how half <a href="https://www.shadertoy.com/">the crazy stuff people do with shaders</a> is done, but getting started using shaders for applying simple effects to 2D textures is not that bad at all. </p><p>Each GLSL shader is split into two parts:</p><ul><li><p><strong>The vertex shader</strong>, which is only really relevant for 3D because it&#8217;s used to mess around with a 3D shape&#8217;s vertices, and so in my case will basically always look the same and not do much. If I wanted to deform the rectangle my texture was being drawn to this might be relevant, but usually I don&#8217;t.</p></li><li><p><strong>The fragment shader</strong>, which is used to mess around with pixel data by changing the position and value of colors on a texture. You can think the actual function written in it as being run on a single point of the texture (the GPU will run it on as many points as needed to construct each pixel of the final output). This is where the magic happens, by passing in a texture here, sampling it, modifying the sampled color, then passing it on, we can create all sorts of neat effects.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p></li></ul><p>And that pretty much covers it! If you want to get started with these yourself, I&#8217;d recommend looking up examples online, but here&#8217;s an example of a shader I wrote that creates a simple wavy effect and pulses the texture red:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!P663!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!P663!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 424w, https://substackcdn.com/image/fetch/$s_!P663!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 848w, https://substackcdn.com/image/fetch/$s_!P663!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 1272w, https://substackcdn.com/image/fetch/$s_!P663!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!P663!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png" width="673" height="276" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:276,&quot;width&quot;:673,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25819,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!P663!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 424w, https://substackcdn.com/image/fetch/$s_!P663!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 848w, https://substackcdn.com/image/fetch/$s_!P663!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 1272w, https://substackcdn.com/image/fetch/$s_!P663!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc587d7e0-bdef-4503-a915-b04cfd4934ca_673x276.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Vertex shader</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KtgT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KtgT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 424w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 848w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 1272w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KtgT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png" width="668" height="371.3849938499385" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:452,&quot;width&quot;:813,&quot;resizeWidth&quot;:668,&quot;bytes&quot;:44361,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KtgT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 424w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 848w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 1272w, https://substackcdn.com/image/fetch/$s_!KtgT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fed441f7c-ae9e-4873-8476-6d8a3568230b_813x452.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Fragment shader. Setting gl_FragColor is what determines the output color. Doing this properly would necessitate passing in information about the sprite and texture page size in pixels, but since this is a quick test I&#8217;m just multiplying by some arbitrary constants.</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IwfA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IwfA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 424w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 848w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 1272w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IwfA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png" width="678" height="349.8576512455516" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:435,&quot;width&quot;:843,&quot;resizeWidth&quot;:678,&quot;bytes&quot;:47466,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!IwfA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 424w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 848w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 1272w, https://substackcdn.com/image/fetch/$s_!IwfA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbfaf0e0-7f3b-44db-a7b3-4219ceb6c73b_843x435.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Example usage in main ODIN program</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZjkA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZjkA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 424w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 848w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 1272w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZjkA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif" width="132" height="134.1639344262295" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:124,&quot;width&quot;:122,&quot;resizeWidth&quot;:132,&quot;bytes&quot;:464414,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZjkA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 424w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 848w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 1272w, https://substackcdn.com/image/fetch/$s_!ZjkA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02391cb8-2ebb-4c3d-8eec-9e3e5a25d310_122x124.gif 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Result, mangled by gif compression</figcaption></figure></div><h1>Serialization</h1><p>You can think of &#8216;serialization&#8217; as just a fancy synonym for &#8220;saving and loading (usually to a file)&#8221;, or, in a dry, useless, technical sense, &#8220;converting data into a stream of bytes for transmission or storage&#8221;. But it&#8217;s worth dissecting the term to understand what it really means: data in computer programs is, underneath it all, just a long string of ones and zeroes. But some of those ones and zeroes are treated as <em>references </em>to other bits of that long string. If I have 100 enemies in my game that all look the same, I don&#8217;t want to copy the texture data used to represent those enemies 100 times, what a waste! So instead, in each of the little data structures that hold each enemy&#8217;s information like position and speed, I keep a small little number that shows you exactly where to find that enemy&#8217;s texture data in some central place in memory. When the rendering system comes along to render that enemy, rather than reading the texture data to pass to the GPU directly from the enemy&#8217;s data itself, it follows that little address and gets it from the central place. This is all well and good, but now let&#8217;s say I want to save all of that enemy&#8217;s information to a file, so that I can load it up later. I tuck all the little numbers in the enemy&#8217;s little data structure into a little binary file and back it up to the cloud.</p><p>Flash forward 70 years. I am old. Too old. My only remaining shot at joy in life is to see that little enemy again. I pull the enemy&#8217;s file down from the hypercloud. Tell me dear reader, using only that file, will I be able to draw that enemy again&#8230;? No! Sure, I&#8217;ll know where that enemy was and how fast it was going, those are just numbers, stored safely in the file. But that little address that showed me where to get the texture data? It points to <em>nothing. </em>The RAM that held that texture data turned to ash long ago. Despair overtakes me, I will never see my enemy again.</p><p>This is what it really means for data to be &#8220;serializable&#8221; or not. If you can reconstruct all the relevant information a block of data is meant to represent by reading through that block alone, a.k.a. that <em>serial </em>string of ones and zeroes, then we can say that any data that can be turned into such a block is <em>serializable</em>. Conversely, data that isn&#8217;t serializable is data which points to outside information using addresses whose validity won&#8217;t outlive the data itself. Note that there&#8217;s a bit of fuzziness here. If I had loaded the enemy file right after saving it, without closing the program, the address pointing to the texture would still have worked (assuming the program didn&#8217;t move the texture data somewhere else for whatever reason). If I never intend to keep enemy files around for longer than the lifetime of the program, then I will always know how to interpret the texture address properly, and the enemy data is, in a limited sense, serializable.</p><p>Anyway, as you may have guessed, serialization comes into play when saving and loading the player&#8217;s progress, as well as when editing data that will get turned into loadable asset files such as stages or cutscenes. The exact details of how one goes about serializing this sort of data radically depends on the details of a specific game, but it&#8217;s important to think about how your data is laid out and to be able to quickly recognize what can and can&#8217;t be easily serialized.</p><h1>Stages</h1><p>A stage system is something that is genuinely so game-dependent that it&#8217;s tough to describe in detail. But <em>broadly speaking, </em>stage systems will look something like this:</p><ul><li><p>Stage data is saved to a file in a format your engine can interpret (i.e. deserialize).</p></li><li><p>These files are edited using and external editor such as Tiled or LDTk, or in-engine using a custom-built level editor. On my current project, I built an editor that can edit entities and a few other things like image and tileset layers directly. When saving, the editor reads only the relevent information from the game state and serializes it to a stage file. </p></li><li><p>When loading a stage, existing entities and other non-persistent stage elements are cleared, and new ones are created using information from the stage file. </p></li></ul><h1>Particles</h1><p>Gonna be honest, haven&#8217;t gotten around to actually building this yet as of writing this. But in principle, this is just a <em>very efficient </em>sprite system that sacrifices versatility and control over individual sprites in order to quickly be able to draw a huge amount of sprites at once. The difference is related to sorts of considerations that come up in Data-oriented design, something I touched on in the post on entities. Basically, the plan when building a particle system is to pack all the information your particles will need in order to be rendered (stuff like position, speed, spin, and texture information) as conservatively as possible into one dense array (it&#8217;s worth looking up other particle systems to get an idea of the kind of variables they use to create effects). You can then churn through this data very quickly, updating and rendering each particle without needing to retrieve data from elsewhere. </p><h1>Other tips and tricks</h1><ul><li><p>A debug console you can call up at anytime is an invaluable tool, and worth building. At its simplest this is just a textbox where you can type in predefined commands which will call custom functions, but adding features yourself such as a history, autocomplete, command arguments, and a visible output is not as daunting as you might think. I use the <a href="https://github.com/ocornut/imgui">dear imgui</a> library to build in-engine development tools like this, and it&#8217;s quite pleasant to work with.</p></li><li><p>Similarly, learning how to set up and use a profiler is not that hard and is indispensable when it comes to evaluating your code&#8217;s performance, and for a language manually managed memory like ODIN it&#8217;s immensely useful for making sure your program isn&#8217;t leaking memory (i.e. requesting memory without properly cleaning it up when its done, an error which will eventually balloon your program&#8217;s RAM consumption and crash it). I recommend <a href="https://github.com/wolfpld/tracy">Tracy</a>, ODIN bindings can be found <a href="https://github.com/oskarnp/odin-tracy">here</a>.</p></li><li><p>Tilesets should just be a small extension to the existing sprite system. Define a structure that &#8220;wraps&#8221; a sprite with a additional information such as tile size and padding. You can then build functionality that takes that structure as well as a given &#8220;tile index&#8221; and draws the relevant part of the sprite, i.e. the tile at the given index.</p></li><li><p>Regularly testing your engine on platforms you plan to support is a good way to catch bugs early and ensure you aren&#8217;t swamped tracking down errors in code you wrote months ago when it&#8217;s finally time to publish. Personally, I have not been keeping up with this, and am therefore screwed.</p></li><li><p>When working in ODIN and using a dynamically linked library, remember to include the library file with your final executable (.dll files on windows). Unlike a pure ODIN package, ODIN bindings just tell your program how to call a library, but if you don&#8217;t include the library itself alongside your .exe your program will fail when it tries to call the library and finds nothing. This does not apply to statically linked libraries (.lib on windows), which <em>will </em>be built into your .exe when compiling.</p></li><li><p>Slightly related to the above point, you can take advantage of .dlls to reload the majority of your engine&#8217;s code <em>while it&#8217;s running</em>, giving you the ability to change functionality without needing to close and reopen your program, which can help a lot with iterative testing. The exact details of this are too technical to cover in this series, but I&#8217;d recommend checking out <a href="https://github.com/karl-zylinski/odin-raylib-hot-reload-game-template">this repository</a> for details.</p></li></ul><h1>Grand Conclusion</h1><p>And there you have it! Thanks a lot for reading, to those who have or are planning to build their own engine I hope this helped make it all seem more approachable, looking back over those 6-ish months of work, it really does seem like modern languages like ODIN have made learning and doing proper low-level game development more accessible than ever before, even on a tight schedule like mine. And for those non-programmers this series is ostensibly aimed at, I hope this demystified a lot of what goes on under the hood of your favorite games and gave you a richer understanding of the medium.</p><p>And for those who are maybe on the fence about jumping into this kind of development, I really hope this gave you the push you needed to give it a shot. While I wouldn&#8217;t recommend it to a complete beginner, it&#8217;s clear to me now that building an engine like this isn&#8217;t the crazy multi-year ordeal some make it out to be, and that it should be a natural step on every game programmer&#8217;s journey. Especially for those developing 2D commercial projects, having to deal with a third-party engine can end up being far more trouble in the long run, and building your own foundation in a data-oriented way will result in a happier development experience and better software for your players. And best part is, you can do stuff like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p539!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p539!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 424w, https://substackcdn.com/image/fetch/$s_!p539!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 848w, https://substackcdn.com/image/fetch/$s_!p539!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 1272w, https://substackcdn.com/image/fetch/$s_!p539!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p539!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png" width="640" height="4800" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:4800,&quot;width&quot;:640,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:919090,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p539!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 424w, https://substackcdn.com/image/fetch/$s_!p539!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 848w, https://substackcdn.com/image/fetch/$s_!p539!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 1272w, https://substackcdn.com/image/fetch/$s_!p539!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c8f3759-746d-40b9-b3af-32093b81aa5e_640x4800.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Credit for original comic goes to <a href="https://www.instagram.com/crondle/?hl=en">crondle</a></figcaption></figure></div><h1>Onto the next thing</h1><p>Alright, I&#8217;m off to have my life entirely consumed by that project. See you soon!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fAlX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fAlX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 424w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 848w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 1272w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fAlX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif" width="599" height="336" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:336,&quot;width&quot;:599,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:152734,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/gif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fAlX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 424w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 848w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 1272w, https://substackcdn.com/image/fetch/$s_!fAlX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7af2c5ef-6622-4fdb-8f99-a6f83f4c662a_599x336.gif 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Stay tuned!</figcaption></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d">&lt;Previous post</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>There are lots of complicated ways of divvying up a stage into partitions, but the simplest one is to just pick a size and split the stage up into big squares of that size. </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I believe this functionality has gotten much much better in the recently released SDL3, but at the time I was figuring this out I had no idea when it would be ready so was stuck with SDL2. Still, this is all kinda moot now, but if you want to know the details please comment below. </p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Annoyingly, since GPUs fundamentally work with stretchable triangles, they don&#8217;t really have an easy way to work with textures as fixed grids of pixels, so I often have to pass in information about a texture&#8217;s pixel size to get certain effects working properly. An easy example of this: say I want to make a shader that shifts everything in a texture to the right by a certain fixed pixel amount when drawing it. If I don&#8217;t know how big the texture is in pixels, I can only shift it to the right by, e.g. 30% of its size. This means larger textures would get shifted more in absolute pixel terms than smaller textures. </p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Audio]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Wed, 29 Jan 2025 06:43:34 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5f5eba9b-8993-4b9f-b7cf-161b8638d3f1_1440x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-ceb">Next Post&gt;</a></em></p><div><hr></div><p>just use FMOD lol</p><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-ceb">Next Post&gt;</a></em></p>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Input]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Wed, 29 Jan 2025 06:38:39 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/bd6becec-4325-4396-b1f1-88ea29c09e45_849x521.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d">Next post&gt;</a></em></p><div><hr></div><p>Input. Seems simple, right? Press the A button, make the marketable character jump. Easy peasy. But what if I want to press the spacebar instead? What about the right trigger? What if I <a href="https://youtu.be/zQNpcX_1Syk?si=jcZrXN9NNUqlfnRj&amp;t=205">only want to use one hand</a>? What if I <em>wanted </em>to press the a button <em>now</em>, but I did it one tenth of a second ago? Everything&#8217;s falling apart. The intern has drizzled conditional input checks all over the player object. You&#8217;re using variables from 5 different files, half of which you don&#8217;t remember making. You&#8217;re tracking input buffers in the player&#8217;s state logic. Nightmare. Nightmare! NIGHTMARE!!</p><p>Like many software development tasks, building a proper input system is an exercise in abstraction. The goal is to translate signals from a controller into actions in the game, but problems arise when thinking of this as a 1:1 relationship. Instead, it&#8217;s often simpler in the long run to construct multiple <em>abstraction layers </em>which store information and mappings and serve to translate concise, high level requests (e.g. did the player make a &#8220;jump&#8221; input?) into questions of the lower level hardware (e.g. did the 3rd face button on the gamepad connected to OS port 2 go from unpressed to pressed within the last 10 frames?).</p><p>Now, the exact construction of these layers is going to vary significantly based on your preferences, needs, and what your framework/engine can already provide for you, but I&#8217;ll describe the system I use, which is fairly generalizable. It involves roughly 4 layers:</p><ul><li><p>The framework layer</p></li><li><p>The abstracted hardware layer</p></li><li><p>The mapping layer</p></li><li><p>The verb layer</p></li></ul><h2>The framework layer</h2><p>Premade engines like Game Maker or Godot will usually get you most of the second layer out of the box, sometimes more, but if you&#8217;re just using a framework like SDL then this is the only part that will already be done for you. In my case, SDL handles two things for me:</p><ul><li><p>Allows me to retrieve the complete input state of the keyboard or mouse at any given point in time as a big chunk of data.</p></li><li><p>Triggers events when a gamepad is connected/disconnected, which provide a pointer that can be used to retrieve infromation about the state of that specific gamepad later on.</p></li></ul><h2>The abstracted hardware layer</h2><p>The goal of this layer is to read the input states obtained from the previous layer and allow us to easily ask, for any given device, whether one of its keys/buttons<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> was pressed, released, or is being held. Also to retrieve the current value of unique stuff like analog stick axes or mouse position. I call it the &#8220;abstracted hardware&#8221; layer because, while we&#8217;re still thinking of physical devices at this point, I&#8217;ll be fully abstracting away anything that isn&#8217;t directly relevant to input; stuff like what exact usb or hardware slot we&#8217;re using, or weirdly formatted analog input values. </p><p>For the most part, we can just pass on slightly reformatted values from the framework layer, but there <em>are </em>two not-so-trivial problems to solve here:</p><ul><li><p>How do you tell if a button has just been pressed/released, given that we can only retrieve the current input state at any given time?</p></li><li><p>How do you handle multiple gamepads?</p></li></ul><p>Taking them in order, the first problem is simple. As mentioned previously, the game runs it&#8217;s logic once per &#8220;frame&#8221;, in my case every 1/60th of a second. While some applications will try to obtain the input state as often as they can, in my case I only have to do so at the start of each frame. But I can also store the input state from the start of the previous frame as well! By doing this, whenever something asks if a key/button was pressed, I just need to check the current state against the previous state. If the button was inactive last frame but is active this frame, that means it was just pressed down<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>!</p><p>The next problem is a little trickier. If you&#8217;re making a singleplayer game you can get away with just polling every connected gamepad for input and treating them like one weird schrodinger&#8217;s gamepad, but if you&#8217;re doing any sort of multiplayer you need to be able to differentiate between each specific gamepad; you need to assign each a unique, persistent ID. </p><p>I see many beginners inclined to just look up a controller&#8217;s &#8216;hardware slot&#8217; (the number sometimes indicated by little green lights on controllers) and use that to identify it. Unfortunately, this runs into a number of pitfalls, mainly because it leaves you completely beholden to what the OS wants to do with this ID. Did you know that on Windows it&#8217;s <em>almost impossible </em>to change what ID a controller has been assigned without restarting your PC? If you plug in two controllers then unplug the first one, well, congrats: barring a restart (or a 15 minute unplug-replug sesh with 3 more controllers) you are Player 2 forever now. The number of games that don&#8217;t account for this is staggering, I&#8217;ve seen some <em>singleplayer </em>games that refuse to read anything from any gamepad except the one in the first slot. So this is a non-starter. </p><p>My recommended alternative is to assign virtual slot numbers yourself, in order, whenever a gamepad is plugged in. If a gamepad is unplugged it&#8217;s slot becomes available to the next gamepad that&#8217;s plugged in, so resetting slots is as simple for the user as unplugging everything then replugging it in the desired order. This does mean stuff can get mixed up if something is accidentally unplugged after someone leaves, but I think the gains in flexibility more than make up for this shortcoming.</p><p>And that&#8217;s that! A layer like this is useful in and of itself when doing stuff like prototyping or simple menus, but if things need to be remapped then we need to move on&#8230;</p><h2>The mapping layer</h2><p>At this point, things would start to get a little more game-dependent. This part of the input system wouldn&#8217;t usually be done as part of the base engine, but the idea can be applied to almost any game so I figured I&#8217;d cover it anyway. I&#8217;ll be assuming the game is singleplayer to keep things simple, but the idea would be the same in multiplayer games, just copied across multiple profiles.</p><p>This layer handles mapping (or &#8216;binding&#8217;) buttons to in-game actions, i.e. defining what will be shown to the player in the in-game input remapping menu. You wouldn&#8217;t typically want to allow this for stuff like simple menus (since the player could inadvertently softlock their program) but, in my opinion, any other in-game action should be on the table here. The exact actions and default mappings will, of course, depend on the game.</p><p>There&#8217;s not much else to say here, this layer basically just exists as a big switchboard. You ask it &#8220;what&#8217;s the button for jumping?&#8221; and it knows it&#8217;s the A button, which it can then pass along to the hardware layer to know whether that button is being pressed.</p><h2>The verb layer</h2><p>Finally, we&#8217;ve reached the end point. Here&#8217;s where things get a little interesting. You might have a &#8220;jump&#8221; button mapped in the previous layer, but sometimes just knowing if the &#8220;jump&#8221; button was pressed this frame isn&#8217;t enough. The main purpose of this layer is to be hardware agnostic (i.e. to check for an action&#8217;s corresponding input regardless of what input device the player is using), but it&#8217;s also used to implement <em>input buffering, </em>i.e. &#8220;storing&#8221; inputs for use in the near future. A common example that&#8217;s often given as a use-case for this goes like so: in platformers, players often want to jump as soon as they hit the ground, but if they press the jump button slightly before landing then the input will be &#8216;eaten&#8217; (since you can&#8217;t jump in midair), which feels terrible. But if you &#8216;buffer&#8217; the input by checking (when grounded) not only if the jump button was pressed this frame but <em>at any point in the last 10 frames, </em>then the player character will jump as soon as they hit the ground even if the input came slightly too early. The exact amount of buffer will vary from action to action and game to game (non-action games usually have no need for it at all), but granting this sort of margin of error goes a long way in making a game feel responsive.</p><p>So the end goal of this layer is to provide a list of &#8220;verbs&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> that can be used to make requests like &#8220;was there a [jump] input in the last 10 frames?&#8221;. You might have noticed that I already do a little bit of buffering in the abstracted hardware layer in order to check button presses and releases, and while I could handle more long-term buffering at that stage, doing it here (by storing a portion of the data from that layer) is a bit more efficient since I only have to keep track of the inputs the player has mapped to an action, rather than the hundreds of possible buttons that <em>could </em>be mapped. </p><p>Each action from the mapping layer usually gets 1-3 verbs (depending if you want to track a button press, release, hold, or some combination of the three). You&#8217;d also have verbs for actions that don&#8217;t necessarily have a mapping, such as left and right movement when using a gamepad (since that&#8217;s usually locked to an analog stick). Again, the point here is to be completely hardware agnostic, the layer will handle identifying what kind of controller the player is using and making the right request to the hardware layer using the correct bindings from mapping layer (or constant values, for actions with no bindings). It stores information for all these verbs every frame in its buffer, and uses this information to answer the aforementioned high-level requests.</p><h2>Conclusion</h2><p>Awesome! And with that, we&#8217;ve covered every &#8220;fundamental&#8221; feature a game engine needs to make an absolutely terrible super bare-bones &#8220;&#8220;&#8220;game&#8221;&#8221;&#8221;! Wow!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a> From now on I&#8217;ll be talking about some important but less totally foundational engine features; join me next time to <em>hear </em>all about the audio system! </p><p></p><p>And by hear I mean read, I will not be including audio.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-b4d">Next Post&gt;</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Referred to henceforth just as &#8220;buttons&#8221;.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>And vice-versa to check if a button was released.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Calling them &#8220;actions&#8221; felt too ambiguous</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Well, we probably didn&#8217;t really <em>need </em>sprites, you could make a game with just, like, rectangles.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Sprites]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Thu, 25 Jul 2024 23:45:51 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/710e491f-1ba1-4d4b-bd51-9fcf2707f034_458x348.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008">Next Post&gt;</a></em></p><div><hr></div><p>Y&#8217;know, I&#8217;ve always wondered why they&#8217;re called that. Wikipedia claims it&#8217;s because they &#8220;float on top of the background image without overwriting it, much like a ghost or mythological sprite&#8221;, but that seems awfully tenuous. </p><p>Anyway, what exactly are we talking about? Well, images! This is fairly common knowledge, but &#8216;sprite&#8217; is the general term for any pre-drawn 2D image you might see in a game. They&#8217;re used to depict anything from characters to scenery to UI elements. One important thing to note: self-contained animations (such as a character&#8217;s walk cycle) might contain several individual images (i.e. animation frames), but they&#8217;re usually considered a <em>single </em>sprite. This makes sense, for reasons we&#8217;ll see later.</p><p>Now, what exactly goes into a sprite system? The goal when building one can be summarized thusly: </p><ol><li><p>Get the drawing from the artist&#8217;s desk.</p></li><li><p>Convert it into something that can be rendered to the screen efficiently by the computer.</p></li><li><p>Make a system the programmer can easily use to tell the computer to do so whenever they want.</p></li></ol><h2>Get the drawing!</h2><p>Our precious, precious artists. They are beautiful, innocent, unsullied. They are not to be exposed to anything as filthy as a command line. As such, I must find a way to automatically retrieve their work. Fortunately, we can make this step a part of our build system (see the previous post for details about that). </p><p>As mentioned last time, artists will be mostly working with Aseprite files. This is great for them, since they have all sorts of editing tools at their disposal and can work on an entire animation at once, but it presents an issue, since most tools can&#8217;t read aseprite files directly. Not to worry though! Thanks to Aseprite&#8217;s scripting API I have the ability to automate the export of these files to some pretty precise specifications. Since I need the individual image data of each animation frame for the next step anyway, I&#8217;ll export each frame stored in the aseprite file as an individual .png<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a> file and store it in a temporary folder.</p><p>One additional wrinkle: I need the image data, sure, but I also need to keep track of some metadata for each frame; stuff like the name of the sprite, the order of the frame, how long it lasts in the full animation, and a custom origin point. .png files don&#8217;t exactly have a predetermined slot for this data, so it&#8217;s not obvious where it would go. One option is to give the file a unique ID then create a separate file when exporting that tracks this data and maps it to the file id (which I&#8217;ll have to do later anyway), but, given that it&#8217;s not actually a lot of data at this point, I can use a neat trick and simplify things by storing that information in the file&#8217;s title! Here&#8217;s an example of an exported 4-frame animation; the folder name keeps track of the name of the sprite and each file title stores the frame index, duration (in milliseconds), and origin point:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c8gO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c8gO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 424w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 848w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 1272w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c8gO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png" width="1180" height="624" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:624,&quot;width&quot;:1180,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:69839,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c8gO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 424w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 848w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 1272w, https://substackcdn.com/image/fetch/$s_!c8gO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe99d1734-bb63-4266-b75c-5cd5d19f6c4d_1180x624.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Convert the drawing!</h2><p>Alright, now that I have the images, I need to be able to render them efficiently in-game! This involves retrieving the image data from the files when the game is running, storing it in a &#8216;texture&#8217; (essentially a blob of image data that lives in RAM), then rendering that texture to the screen using the GPU. The framework I&#8217;m using can do this by loading .png files directly into their own individual textures and using those, but this should be avoided for two reasons:</p><ol><li><p>A game can end up having thousands or even tens of thousands of individual animation frames. Loading them all into memory separately while the game is running would involve just as many filesystem calls, which as I&#8217;ve mentioned before can be quite bad for performance.</p></li><li><p>This one&#8217;s more important, and the reason we can&#8217;t use a simple asset packer to get around the first problem: rendering a texture involves the CPU moving it from RAM to the GPU and&#8230; hm, I feel I should maybe explain these terms&#8230;</p></li></ol><h2>Sidebar!</h2><p>Well dear reader, you&#8217;ve done great so far, but it&#8217;s unofrtunately time to subject you to another computer science lesson (tragic). If you know what a GPU is you can skip ahead to the next heading, but for everyone else, sorry, but I&#8217;ve already locked the doors. Now then, in <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-901">the second post in this series</a> we talked a bit about the CPU and RAM. As a quick refresher:</p><ul><li><p>The CPU (Central Processing Unit) is the part of your computer that does most of the &#8220;work&#8221; by moving bits of data to and from memory and running simple opertions on them.</p></li><li><p>RAM (Random Access Memory) is the type of memory in your computer that&#8217;s only used while the computer is on. It&#8217;s faster to access than permanent storage like your hard drive, and most or all of a program&#8217;s information will be stored here while that program is running.</p></li></ul><p>Understanding these is enough to get an idea of what most programs are doing, but once we add certain tasks (like graphics) into the mix, we have to start talking about the GPU! If you&#8217;re unaware, that stands for &#8216;Graphics Processing Unit&#8217; (big surprise). It&#8217;s a processing unit just like the CPU in the sense that it receives data from memory, does stuff to that data, then sends it on it&#8217;s way. In fact, older PCs didn&#8217;t even have any, they weren&#8217;t even invented until the late 90s! So what exactly is the difference? </p><p>It all comes down to something called <em>parallelism</em>. Take the following computing task:</p><ol><li><p>Read number a and number b from memory.</p></li><li><p>Add them together.</p></li><li><p>Take the result and divide it by 2.</p></li><li><p>Save the result to memory as number c.</p></li></ol><p>This task can be described as <em>sequential</em>, that is, each step depends on the result of the previous step. More accurately, you would say it&#8217;s impossible to do better than the sequential approach when trying to complete this task. Now let&#8217;s take a look at a different example:</p><ol><li><p>Read number a, number b, and number c from memory.</p></li><li><p>Add 4 to number a.</p></li><li><p>Subtract 2 from number b.</p></li><li><p>Multiply number c by 0.</p></li><li><p>Save the results to memory in-place.</p></li></ol><p>One thing you might have noticed here: none of the operations on the numbers here really depend on what&#8217;s going on with the other numbers, which means this problem is <em>parallelizable, </em>i.e. the steps can be worked on in parallel. </p><p>To use a simplified analogy, let&#8217;s say your CPU contains 3 little worker elves. If you gave the elves the first task, it doesn&#8217;t really help that there are three of them. Even if each elf is assigned it&#8217;s own steps, the elf assigned to step 2 would still have to wait around for step 1 to finish, and the elf assigned to step 3 would have to wait for steps 1 and 2 to finish. This means it would take the same amount of time for one elf to do all the work as it would take for 3, 10, or even 100 elves! In fact, more elves might take longer, since they need to pass things around to each other. But when it comes to the second task, more elves helps a lot! Each elf can work on its own number without caring about what the other elves are doing, and things get done 3 times faster than if one elf had to go through all three numbers itself!</p><p>So what does this have to do with anything? Well, you can think of the main difference between the CPU and GPU as being their ability to work on things in parallel. For a while, CPUs could <em>only </em>work on tasks sequentially, and this is still their main strength today. The CPU in your typical home computer has about 2-8 elves (or, er, &#8216;cores&#8217;). Now, these are really jacked elves, they eat their protein powder and drink their juice; they can churn through tasks <em>really </em>quickly. But there are only 8 of them. Conversely, GPUs can have <em>thousands </em>of cores. Now, most computing tasks are sequential, the only way you&#8217;re getting things done faster is by getting a faster single core. But certain classes of tasks (such as, surprise surprise, graphics) are referred to as &#8216;embarassingly parallel&#8217;, which means more cores &#8594; faster performance. </p><p>To make this a little more salient, let&#8217;s take a typical graphics task: drawing a tinted HD image to the screen. There are 2,073,600 pixels in an image that size (1920x1080). If I were doing things sequentially, I&#8217;d have to operate on the color data of each individual pixel one at a time; <em>millions </em>of operations. But none of the pixels care what the other pixels look like. With a GPU, each core can work in parallel to work on thousands of pixels at a time, drastically speeding up the operation. Waow!</p><h2>Where were we?</h2><p>Huh? Oh yeah, sprite packing. So, why can&#8217;t all my sprite frames stay in their own little .png file? This is because, in order to get the GPU to do anything, the CPU has to send the data relevant to the task to it from RAM, which can often be the slowest part of the process. If each sprite is stored as its own texture in memory, then I&#8217;d have to send over a new texture every single time I want to draw a sprite, very slow. </p><p>So how does one get around this? Well, textures can get very big; many modern GPUs support textures up to 4096x4096 pixels in size, and almost all support textures up to 2048x2048 pixels. Since most sprites are much smaller than this (especially ones in a retro-style pixel-art game), this means I can &#8220;pack&#8221; more than one sprite on a single texture! When drawing a sprite frame, I send this whole giant texture, then tell the GPU to only draw the specific part corresponding to that specific frame. This might seem wasteful, and it would be if I was doing this every time I wanted to draw the sprite frame, but organizing things this way allows me to &#8220;batch&#8221; draw calls. Instead of sending the texture over every time I want to draw a sprite, I instead keep the drawing instructions in reserve. When it&#8217;s time to present a finished render to the screen, I send the whole texture over <em>along with all the saved up instructions at once. </em>This means the GPU will happily draw a bunch of sprites all using the same texture!</p><p>So how do I get these &#8216;packed&#8217; textures? It&#8217;s technically possible to load a bunch of separate .pngs into one texture when the game starts up, but, as mentioned, it&#8217;s better to do this step ahead of time. This means packing all my smaller .pngs into one big .png known as a &#8216;texture page&#8217;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a> (a.k.a. texture atlas, sprite atlas, or sprite sheet<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>). At this stage, since sprites are no longer split up into a bunch of different files, I also produce a separate &#8216;index&#8217; file for each texture page that keeps track of sprite frame metadata (the stuff we saw earlier, like frame index and duration, as well as where that frame is positioned on the texture page). I can then read the data from this file when drawing to calculate the exact instructions I need to send to the GPU.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1Xrx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1Xrx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 424w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 848w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 1272w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1Xrx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png" width="1437" height="301" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:301,&quot;width&quot;:1437,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39486,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1Xrx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 424w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 848w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 1272w, https://substackcdn.com/image/fetch/$s_!1Xrx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa86fae67-f3a2-41d5-8473-af7d3715a745_1437x301.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">Example of a (small) finished texture page.</figcaption></figure></div><h2>Make a system the programmer can easily use to tell the computer to draw sprites whenever they want!</h2><p>Ok! Ok! We sort of already covered most of this in the previous section, but here are some neat things I included in my sprite system to make using it easier:</p><ol><li><p>Part of the build process saves each sprite&#8217;s name to a code file in a special way that lets me refer to each sprite directly by name when scripting.</p></li><li><p>The most basic way to draw a sprite is by providing the sprite, as well as a position. I built my system to be able to do this by without the requester needing to deal with any of the texture page stuff.</p></li><li><p>Normally, when drawing a sprite at a given position, it will draw the top-left corner of the sprite there. To make things easier on me and the artists, I added the ability to specify a special &#8220;origin&#8221; layer in Aseprite, which is tracked by the exporting script. I mentioned this briefly earlier, but basically the &#8216;origin&#8217; is the point on the sprite that will drawn at the given position. Being able to change this makes it easier to reason about where to draw a sprite (e.g. we usually want every entity&#8217;s position in a platformer to be set at their feet. If their sprites were of different heights, we&#8217;d have to determine where the top of the sprite would go for each entity in order to draw it. But by setting every entity&#8217;s sprite&#8217;s origin at that sprite&#8217;s feet, we can simply draw the sprite at the entity&#8217;s position with no adjustment necessary!). The origin can also be used as the rotation axis when drawing the sprite at an angle.</p></li><li><p>Scaling the sprite means mapping it to a differently sized rectangular area, but it&#8217;s often easier to think about multiplying a sprite&#8217;s scale. I wrote some code that lets me use that method instead, it also scales relative to the origin, so e.g. an enemy that gets scaled up will still have its feet on the floor.</p></li></ol><h2>Nice!</h2><p>Yup.</p><p>Next time I&#8217;ll talk about the input system, stay tuned!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-008">Next Post&gt;</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>We use .png files since they&#8217;re a lossless format that simply stores the image as-is. While it&#8217;s technically possible to use a compressed format like .jpg, this would be counterproductive: compression would damage the image quality of sprites, and rendering the sprite would require either decompressing it ahead of time (defeating the point of compression), or slowly decompressing it whenever it needed to be rendered, which would be terrible for performance. The only time this <em>might </em>make sense is for <em>extremely </em>large image files.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>There are several existing software tools that can do this, google &#8220;texture packing&#8221; and pick your favorite!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Not to be confused with the &#8216;sprite sheets&#8217; you might have seen on websites like The Spriter&#8217;s Resource. These are usually reconstructed manually by extracting image data from game files and lining it up in an appealing way. They are meant to serve as a clean reference for artists rather than an optimized chunk of data.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Building the Game]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Fri, 05 Jul 2024 06:06:59 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5a754d45-d104-4ac1-87ec-1ded0c4f73af_1198x797.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc">Next post&gt;</a></em></p><div><hr></div><p><em>I released a demo video recently showing off a bunch of the engine&#8217;s basic features! Here it is in case you missed it:</em></p><div id="youtube2-jUHQJ-m6xOI" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;jUHQJ-m6xOI&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/jUHQJ-m6xOI?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><em>I&#8230; might be a bit further ahead than these posts maybe had you believing. Can&#8217;t spend all my time on my blog after all! So, uh, sorry for spoiling the next few posts I guess.</em></p><div><hr></div><p>Now that the engine code has a functional core in the entity system and game loop, I can start actually writing code that will, y&#8217;know, do stuff.</p><p>Like the test app I wrote, setting up a display system involves just a few calls to the framework<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. I&#8217;ll talk about what goes into a fully-fledged display system more in a later post, but for now I&#8217;m just setting up a simple texture I can draw to and clear every frame (sort of like a digital canvas), then scaling that texture to an application window displayed to the user. Once that&#8217;s done, I can write code in the main loop or in entity components that draws stuff to that texture, and it&#8217;ll show up on screen!</p><p>At this point I&#8217;m still kind of limited though. The framework provides functionality for drawing &#8216;primitives&#8217; like lines and triangles, but last I checked it&#8217;s not 1962 anymore, it&#8217;s <em>at least </em>1974<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>; time to get some sprites in! To do that, I&#8217;ll need to load some kind of image data into memory. I could just use the framework to load individual .png files directly, but once a game starts using a lot of sprites this can get quite slow for several reasons, so I&#8217;ll want to pack sprites into larger image files. Also, hm, how am I gonna organize all those files? These are <em>animated </em>sprites, each frame is its own image file! And anyone doing art is probably gonna be using a program like aseprite, are they gonna have to export and sort everything themselves? And where am I gonna put other assets like text files or sounds? Come to think of it, compiling the engine code manually every time from my command line is getting kinda tedious&#8230; </p><p>Ok, it&#8217;s about time to set up a <strong>build system</strong>.</p><h2>What&#8217;s that?</h2><p>Build systems come in many shapes and forms, but they can generally be defined as &#8220;automated processes that turn a program&#8217;s source code and other asset files into a set of files that can be run directly&#8221; (for simple programs, you could consider the &#8220;build system&#8221; as just being the compiler which turns your source code into a single .exe file that anyone can run, but, as we just saw, more complex programs like games tend to have more elaborate requirements). If you pop open your steam directory and open up any game&#8217;s install folder, you won&#8217;t (often) be able to see a game&#8217;s source code or view/edit its assets directly, what you&#8217;re seeing instead is the output of that game&#8217;s build system.</p><p>So what are my goals? Actually, pretty specific. The shortcomings of Game Maker&#8217;s build system remain a thorn in my side to this day, creating something that avoids making the same mistakes is a huge reason I&#8217;m developing my own engine in the first place. With that in mind, here&#8217;s the plan:</p><ul><li><p>Any part of the game&#8217;s files that can be built individually should be. No need to rebuild every sprite when changing a line of code.</p></li><li><p>An automated file watching system to ensure that files are rebuilt as soon as a change is detected. This means the build system is always running in the background to ensure the game is ready to be launched as soon as possible. Normally, a build system would only start running the moment the user manually triggered it, forcing them to wait for it to finish before the program actually launched. This helps avoid that<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a>.</p></li><li><p>Asset packing, which is basically just squeezing the raw data from multiple asset files into one big file that&#8217;s just a blob of ones and zeroes. This speeds up loading times in-game by reducing the amount of file-system requests I need to make, as well as slightly obfuscating the assets to make it harder for inexperienced users digging into the game files to mess with them.</p></li><li><p>Support for building .aseprite files. Aseprite is basically the industry standard for pixel art, and is what&#8217;s typically used to make the bulk of the art and animations for the sorts of games I&#8217;m developing. Unfortunately, like most image editing programs, it&#8217;s not standard <em>enough </em>that its project files can be directly read in the same way that .png files can. This usually means that aseprite project files need to be exported to a set of intermediary files in order to actually be legible. But automating this process as part of my build system (as well as exporting additional data such as frame timings) would allow me and other team members to work directly on aseprite files and see the results reflected in-game without any need to manually export things, a huge quality-of-life improvement.</p></li><li><p>A quick way to both run the current build and to initiate a new build from scratch. Having e.g. a keyboard shortcut to run the game makes it nice and easy to test changes on a whim. And initiating a build from scratch might take longer than running using any existing built files, but it&#8217;s a crucial ability to have given the automated file watching process might introduce errors or fail to keep up in rare cases.</p></li><li><p>Ability to &#8216;hot-reload&#8217; assets at runtime. What this means is that it should be possible to change a non-code asset after the game has been launched and see the changes show up in-game. Now, there&#8217;s a limit to how robust this can be without putting in a ton of effort, but even a simple, slightly unstable version of this is incredibly useful as a developer-only tool.</p></li><li><p>Speed! The build system should be as fast as possible, wherever possible. This is a huge deal when it comes to iterating on a game, you want to be able to see changes you make reflected in-game as soon as possible. If it takes too long, your attention will wander and maintaining a tight iterative feedback loop in your own head becomes much harder. Say you wanted to tune a character&#8217;s walking and running speed to be <em>just </em>right. How much easier would that be if it took half a second for your changes to show up vs. 7 minutes? You might have noticed a lot of the features listed here are designed to cut down on the time a developer spends idly waiting; that&#8217;s all in service of the same goal.</p></li></ul><p>Lofty goals! So how do I go about making something like this? It can&#8217;t quite be a part of the rest of the source code, that&#8217;s what we&#8217;re trying to build after all! In theory, I could also make all this using odin, it would just be a smaller, simpler set of programs that would be stored and compiled separately. This might even be one of the more performant options. But to be honest, it&#8217;s not exactly what the language was built for. A systems language makes sense when you&#8217;re trying to quickly manipulate a large, complex set of data in RAM. But most of the operations involved in a build system will either be requests to the filesystem or to other programs, which means the program instructions themselves won&#8217;t make up that large a portion of the overall execution time. </p><p>In that case, it makes more sense to look at a some sort of scripting language designed for these sorts of operations. The gain in ergonomics from e.g. not having to constantly recompile small programs (since interpreted scripts can just be run directly without needing to first compile them) or deal with odin&#8217;s more finicky text string manipulation seems like it would greatly outweigh the possible performance downsides. A popular language like python or lua could do the trick, but ultimately I decided to write most of my scripts in powershell, microsoft&#8217;s scripting language designed specifically for these sorts of tasks. And yeah, even at first glance it&#8217;s obvious that powershell makes it very easy to do file operations and to execute command line programs (it&#8217;s also probably as optimized as it gets for that sort of stuff&#8230; for an interpreted language). There&#8217;s definitely some syntax weirdness in other places, but it&#8217;s clearly the right tool for the job.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a></p><p>Still though, the self-contained nature of each script makes it much easier to incorporate other tools into the build system. Jumping ahead a little, I ended up using a small lua script as part of the sprite exporting process to take advantage of aseprite&#8217;s scripting API, and the aformentioned asset packer ended up being written as a small odin program, since it involves manipulating a lot of raw data.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a></p><h2>And file watching?</h2><p>So, tracking changes to files is a problem without an obvious approach. A while back, my thought was that I&#8217;d have to keep some kind of ledger that could be quickly checked against every time a build occured to see if anything had changed. Fortunately, after looking into it some more, I found out that there are a number of fleshed out <strong>file watching </strong>programs that can be customized to suit one&#8217;s needs. A file watcher is a program that runs in the background and periodically checks a specified directory for changes, and which can do stuff in response. I&#8217;m sure the details of how it does this efficiently are fascinating, but fortunately I won&#8217;t have to bother with them!</p><p>I decided to go with Watchman, a program developed at Facebook. It seems to be intended more for web stuff, but it&#8217;s simple and versatile enough to work well for me. By setting up a series of &#8220;triggers&#8221; (again, via a powershell script), I can have watchman pass information about individual changed files to my other scripts, to do with what they will.<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a></p><h2>Waow!</h2><p>That&#8217;s pretty much how the build system works, at a high level. To summarize, Watchman is initialized the first time the user builds the game, watches for changes in files in a project&#8217;s asset folder, and any changed files get processed by scripts and outputted into a dedicated &#8216;build&#8217; folder. The build in this folder can then be run using a special script, tied to a keyboard shortcut, that makes sure everything&#8217;s done building correctly before opening the game&#8217;s executable.</p><p>For code, rebuilding is about as simple as calling the odin compiler whenever a change is detected in a .odin file<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>, but other types of assets each have their own special little process. Since each process closely tied to how that type of asset is used in-engine, I&#8217;ll talk more about them in detail when I get around to how that asset type is handled. And in fact, next time I&#8217;ll get back to the sprites, so look forward to it! But for now, you can check out the build system in action in the demo video linked above!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-6fc">Next post&gt;</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>See <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-901">this post</a> for more information about game dev frameworks.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>I really hope wikipedia got these dates right.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>The more astute among you might realize that this tactic won&#8217;t help that much in cases where the user makes a change then wants to run the game <em>immediately</em>,<em> </em>but it&#8217;s often the case that some change will be made long before the user wants to actually run the game (such as when pulling a change from a remote repository or making several edits in a row to different assets). In cases like these, it prevents rebuilding work from piling up. It also eliminates the need to manually track and initiate rebuilds of specific individual assets.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Also, since powershell is part of the Windows OS, scripts can be run very easily, and it&#8217;s one less thing that needs to be installed for anyone else trying to use the engine. This does unfortunately lock me even more into working on Windows, but, frankly, being able to test on the actual OS that most end users will be on is the <em>main</em> reason I&#8217;m stuck here. If you don&#8217;t have this problem, do your part and switch to linux today!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>How exactly am I packing my assets? There are a lot of solutions out there for asset packing file formats, but the problem seemed easy enough that I ended up deciding to just write my own dead simple format. This gets a bit technical, but essentially I&#8217;m just writing a stream of raw bytes to a file. For each type of asset, the program will search a provided directory for the requisite files. It then writes the type of asset (each type is a assigned a numerical ID) and the number of assets of that type. Then, for each file, it writes the size of the file in bytes along with the raw data from that file. Then, once the game is running, I can load all the packed assets from the file just by running the same process in reverse.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>One convenient Watchman feature: when restarting the program, it will treat all existing watched files as newly changed, which means it will pass them all along to their corresponding scripts at once. This makes it very convenient to build the game again from scratch!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p><em>About </em>as simple. I ended up deciding to autogenerate some code for components due to the limitations of Odin&#8217;s strict type system, as well as wanting to add a pinch of syntactic sugar of my own in component event code using special comments. Fortunately this turned out to be not that bad.</p><p></p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: The Game Loop]]></title><description><![CDATA[How do framerates actually work?]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Tue, 18 Jun 2024 03:25:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7a74bb5e-661d-463a-a72f-3583739c6cc6_419x263.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-c31">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a">Next post&gt;</a></em></p><div><hr></div><p><em>(Note: not to be confused with the game design term)</em></p><p><a href="https://gameprogrammingpatterns.com/game-loop.html">Game Programming Patterns has a pretty good chapter on these</a>:</p><blockquote><p>If there is one pattern this book couldn&#8217;t live without, this is it. Game loops are the quintessential example of a &#8220;game programming pattern&#8221;. Almost every game has one, no two are exactly alike, and relatively few programs outside of games use them.</p></blockquote><p>If you have some intermediate coding knowledge you might be better served by that article, but I&#8217;ll try to summarize for the rest of you.</p><p>If you think of a whole program as a big tree of nested function calls (i.e. a bunch of code which executes more code which executes more code), then this is the root. A game (actually, almost any modern application) doesn&#8217;t end until the player asks it to stop. This means it needs to keep running in an endless loop until that happens, continuously waiting for input and reacting to it when that happens. Most games also differ from modern applications in that things keep happening even when the player isn&#8217;t touching anything. Enemies keep moving, animations keep animating, physics keep being simulated, etc. This means that, once the game is initialized, you naturally end up with a looping set of instructions like this:</p><ol><li><p>Read the player&#8217;s input</p></li><li><p>Update the game (physics, player character, enemies, logic, animations, etc.).</p></li><li><p>Draw the updated game state to the screen.</p></li><li><p>If the player didn&#8217;t quit, go back to step 1. Otherwise, close the game. </p></li></ol><p>Easy-peasy, right? Well, not quite. If you set up some code to run in an endless loop, it will just run as fast as the CPU will allow it to. This means that, depending on several factors such as the hardware or how intensive the game&#8217;s current workload is, the game will run faster or slower, resulting in constant fluctuations in the simulation speed. For example, say I set an enemy to move forward by 0.1 units on every loop. The loop might run 500 times per second on my PC, but only 100 times every second on B-san&#8217;s PC. This means the enemy would be moving 50 units per second for me, but only 10 units per second for B-san. <em>Well </em>too slow. Poor B-san. So, how do we fix this? There are multiple options:</p><h2>Delta Time</h2><p>Pop open any beginner Unity tutorial and they&#8217;ll tell you to make sure you&#8217;re multiplying all your speed values by a special value called &#8216;delta_time&#8217;. This is because the Unity&#8217;s default &#8216;Update&#8217; functionality is basically a loop like the one described above; it runs as fast as possible. To account for this, the engine keeps track of the delta_time value, and provides it to you. This is basically the time, in seconds, between when the last loop started and when it ended. By doing things like multiplying speed values by this number, you can have the game simulate things &#8220;consistently&#8221; even if it&#8217;s running at different speeds.</p><p>Let&#8217;s take a look at our previous example. I set my enemy&#8217;s speed; assuming I want it to move 50 units per second I would set the speed value per loop to be 50 multiplied by delta_time. Let&#8217;s take a look at how this play&#8217;s out on my vs. B-san&#8217;s PC:</p><ol><li><p>On my PC, the loop runs on average 500 times per second. This means delta_time usually about 0.002 (1/500). This means my enemy will move 0.1 units per loop (50x0.002), which, lo and behold, adds up to 50 over 500 loops.</p></li><li><p>On B-san&#8217;s PC, the loop runs 100 times per second, so delta_time is 0.01 (1/100). This means the enemy moves 0.5 units per loop (50x0.01) which, once again, adds up to 50 over 100 loops. Hooray!</p></li></ol><p>Anyway, using this sort of thing for any kind of physics code is idiotic. Sorry, unity tutorials.</p><p>Say that, as a completely sane person trying to prove a point, I throw my laptop in the oven. The fans can&#8217;t keep up, everything heats up, the CPU starts throttling and everything slows down drastically. My loop now runs only 2 times every second. The enemy starts moving 25 units per loop. Sure, in theory they&#8217;re moving the same speed as before, but now they&#8217;re snapping around, phasing through walls, the simulation starts breaking, the floors start melting, chaos. </p><p>The issue here is that, while this method smoothly can handle fluctuations in hardware speed, it won&#8217;t produce perfectly consistent results. This makes it fine (or even preferable, for reasons we&#8217;ll see later) for stuff like camera movement, visual effects, animations, etc. since you could, in-principle, throw all that stuff out at any given moment and just (mostly) rederive it from the state of the game world without causing anything but a slight visual hiccup. But for anything that will the game relies upon in subsequent loops (such the position of the player, enemies, timers that affect what state they&#8217;re in, etc.) even small variations will propagate and cause significant differences in the overall state of the game. So what&#8217;s the alternative?</p><h2>Fixed Update</h2><p>In our original example, the game ran at varying speeds, but if you were observing the game from loop iteration to loop iteration without caring about how fast each loop was running then everything would appear consistent (i.e. the enemy would move the same distance over 100 loops on both my and B-san&#8217;s PC, it would just take longer in real-time on B-san&#8217;s side). If we had a way to ensure each loop took the same amount of time no matter what, this would fix the problem.</p><p>Despite the dismal state of it&#8217;s (mostly unofficial) introductory material, the Unity engine itself is naturally aware of this situation and provides an alternative &#8216;FixedUpdate&#8217; functionality specifically for physics code. And Game Maker&#8217;s normal &#8216;Step&#8217; functionality just does this by default (and requires that you do some questionable fiddling to even get it to work in the other way). But how does it work?</p><p>Step one involves picking a target game speed, i.e. how many times per second you want the loop to run. You may have noticed that I&#8217;ve hesitated to call this game speed the &#8220;framerate&#8221; so far; many engines will do so simply because the visual framerate is a natural number to use as your game speed<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. However, many games use a fixed loop for physics tasks that isn&#8217;t tied to the visible framerate (for example, Minecraft servers typically run at a fixed 20 &#8216;ticks per second&#8217;, while the visual framerate can vary significantly). But if you want to keep things simple, 60 &#8220;fps&#8221; is a natural choice for this, since it lets you update the game then draw the updated result once per loop. It also results in a <em>fixed </em>delta time of about 16.67 milliseconds (1/60*1000).</p><p>Now that we have our target framerate and delta time, step two involves inserting a variable <em>delay </em>into the loop. Think of each loop as a block of 16.67 milliseconds that we need to fully occupy, we put all of the game tasks at the start of the loop then fill whatever time is left with a delay period. To do this, check the time at the start of the loop, run all the tasks for that loop, then check the time again. Subtract the time at the start with the latest time to get how long it took to do all the tasks, then subtract <em>that </em>result from the target delta time. This tells you how long you need to delay for. Going back to our original example, doing the tasks might take different amounts of time, about 2ms on my PC vs. 10ms on B-san&#8217;s PC, but this is all evened out by the added delay (14.67ms for me vs. 6.67ms for B-san). Hooray!</p><p>But&#8230; is it real hooray&#8230; this time&#8230; ??? ?</p><h2>Lag</h2><p>The big issue with using the fixed loop method for everything is <em>lag</em>. What happens when the time it takes to run tasks is higher than the target delta time? In cases like these, there&#8217;s unfortunately no way around slowing down the game. This feels pretty terrible even if the slowdown is minor, it makes the game unplayable on sufficiently weak hardware, and even on computers that can run the game fine most of the time, it can seriously damage the play experience during particularly performance-intensive periods. </p><p>It also means players with better hardware can&#8217;t take advantage of it to produce a visually smoother experience. This matters less for retro-style 2D games, but for 3D games or games that use 3D elements like models with interpolated animations or smooth cameras it&#8217;s a pretty silly limitation. </p><p>As we saw in the delta time section, this is not a limitation shared by the other method. Sure, the game might get choppier under worse circumstances, but it will remain decently playable under far worse conditions. This means that, unsurprisingly, best prescription for combatting the problem of lag and variable hardware speeds is an approach that combines both methods.</p><p>And that approach is&#8230;</p><p>Not something I really care to look into.</p><h2>Huh???</h2><p>Yeah, for the (retro-style 2D) games I&#8217;m making, a simple fixed loop approach is more than good enough. I might tweak things a little to account for slight differences in monitor framerates, but the overall approach will be the same. Also, while it&#8217;s possible that I&#8217;ll change my mind about this in the future, part of the point of making my own engine is to gain the ability to develop games where lag isn&#8217;t really an issue (on any modern device at least), so mitigation strategies become less essential.</p><p>Game loops are difficult to talk about comprehensively. Since they&#8217;re at the root of your program, they&#8217;re necessary from the beginning, but they&#8217;re also constantly changing alongside the rest of things. At a certain point, once the engine is in more of a finished state, I&#8217;ll probably make a part 2 detailing exactly what I chose to put in mine, but for now this should cover everything I had to consider starting out.</p><p>Well, that&#8217;s one thing down when it comes to really stress-testing this engine. Next week I&#8217;ll talk about the thing I&#8217;ve spent the better part of last month working on: the build system!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-c31">&lt;Previous post</a> | <a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-86a">Next post&gt;</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Many retro games ran at just about 60 loops per second for the same reason that the NTSC standard for analog TV, used in Japan and most of the Americas, runs at around either 30 or 60 fps: the 60hz AC power supply. Resources were limited at the time, so game speeds were tied to the speed of the hardware itself, which was tied to the speed of the power supply. However, PAL, the standard used in most of Europe and the rest of the world, was designed with a 50hz power supply in mind. This is why the &#8220;PAL&#8221; versions of old games often ran 20% slower than normal, developers could not be bothered to properly adjust for the difference in hardware speed.</p></div></div>]]></content:encoded></item><item><title><![CDATA[So, what *are* we calling these?]]></title><description><![CDATA[My tweet popped off]]></description><link>https://blog.massimogauthier.com/p/so-what-are-we-calling-these</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/so-what-are-we-calling-these</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Thu, 06 Jun 2024 19:24:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!lMeT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About a week ago I tweeted this out:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lMeT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lMeT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 424w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 848w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 1272w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lMeT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png" width="373" height="455.4526315789474" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:812,&quot;width&quot;:665,&quot;resizeWidth&quot;:373,&quot;bytes&quot;:632891,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lMeT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 424w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 848w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 1272w, https://substackcdn.com/image/fetch/$s_!lMeT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffe5670ee-bb1d-4c38-9bd8-06ccdc3546a6_665x812.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It spread, uh, maybe a bit further than I was expecting:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ahce!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ahce!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 424w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 848w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 1272w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ahce!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png" width="664" height="138" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:138,&quot;width&quot;:664,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5901,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ahce!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 424w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 848w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 1272w, https://substackcdn.com/image/fetch/$s_!Ahce!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F564b8109-72a0-4b69-b2b3-d7e7f3c5a0c8_664x138.png 1456w" sizes="100vw"></picture><div></div></div></a></figure></div><p>Now that I&#8217;ve had some time to mull over the reactions, I thought it might be fun to revisit them after presenting a more complete thesis.</p><p>It&#8217;s not unexpected that a lot of people&#8217;s default assumption was that I was trying to identify some kind of subgenre. Truthfully though, I didn&#8217;t have anything so definite in mind. In the replies to the original tweet, I included a list of characteristics which I picked out as the set of combined elements which I thought tied these games together in my mind:</p><blockquote><ul><li><p>Exploration-focused.</p></li><li><p>Very "free", open-ended traversal.</p></li><li><p>Very hands-off tutorialization.</p></li><li><p>Major content locked behind secret, optional, and often difficult puzzles.</p></li><li><p>"Layered" secrets, "endings" that aren't really endings.</p></li><li><p>Rich lore is present or heavily implied.</p></li><li><p>Game knowledge is a major part of progression, veteran players can breeze through off knowledge alone.</p></li><li><p>Minimal focus on action gameplay; action challenges, if any, can often be circumvented with tools/knowledge gained from exploration.</p></li><li><p>Often features small puzzle-solving elements separate from wider exploration.</p></li><li><p>Players often describe their experience with these games as deeply meaningful and/or mind-blowing.</p></li></ul></blockquote><p>I was pretty much just trying to draw a circle around games which share all of these characteristics; even at the time, &#8220;subgenre&#8221; didn&#8217;t really feel like an appropriate label for the category.</p><p>So, what was I even searching for? We&#8217;ll get to the snappy label in a second, but if I now had to summarize the core thing that these sorts of games have in common it would be this:</p><p><em>Each game involves the player mastering a <strong>bespoke</strong>, <strong>predictable</strong>,<strong> </strong></em>and <em><strong>systemic </strong>environment <strong>as a whole</strong>, primarily through the <strong>open-ended</strong></em> <em>and <strong>unguided </strong>gathering of <strong>knowledge</strong></em>.</p><p>As promised, let&#8217;s test this thesis by responding to some of the replies to the original tweet. I&#8217;m sure everyone&#8217;s put just as much thought into this important question.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JMj9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JMj9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 424w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 848w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 1272w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JMj9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png" width="1336" height="1284" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1284,&quot;width&quot;:1336,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:359728,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JMj9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 424w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 848w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 1272w, https://substackcdn.com/image/fetch/$s_!JMj9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F690b0cdb-5678-4faf-a53a-4f416f7eb59e_1336x1284.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Thanks guys.</p><p>On a meta note, while writing that tweet I do recall heeding a raspy, goblin-like voice saying &#8220;phrase it like thisss, it will bring more engagement!&#8221; so I suppose I set myself up for this. And the tweet probably did spread a lot further than it would have if I had instead made a rambling thread full of caveats and clarifications. Which is probably&#8230; good? Yeah. Probably.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PXt8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PXt8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 424w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 848w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 1272w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PXt8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png" width="745" height="148" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:148,&quot;width&quot;:745,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19969,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PXt8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 424w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 848w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 1272w, https://substackcdn.com/image/fetch/$s_!PXt8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb32025e5-5ae1-4ea8-a262-e5dd4fc027fd_745x148.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vSpN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vSpN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 424w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 848w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 1272w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vSpN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png" width="738" height="183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:183,&quot;width&quot;:738,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28583,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vSpN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 424w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 848w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 1272w, https://substackcdn.com/image/fetch/$s_!vSpN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbd648f2c-ad27-4385-b3cc-e928543524f8_738x183.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Yvib!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Yvib!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 424w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 848w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 1272w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Yvib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png" width="734" height="210" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:210,&quot;width&quot;:734,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:36927,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Yvib!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 424w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 848w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 1272w, https://substackcdn.com/image/fetch/$s_!Yvib!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa26bf7c4-f59c-4e98-a094-1c9fa687ae11_734x210.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I feel this is a kneejerk reaction to certain people trying to make these kinds of categories more authoritative than they have any right to be, and I understand wanting to push back against that. But I hope I made it clear that there <em>is </em>something worth pointing to here, and not all efforts of this kind are pointless navel-gazing. As I touched on in a reply to grayfruit, I don&#8217;t think that we would be seeing the same level of experimentation, iteration, and ultimately <em>results </em>we see with metroidvanias if &#8220;metroidvania&#8221; wasn&#8217;t a coherent category with a lot of shared understanding around it. Without a cultural touchstone like this, quickly communicating what your game is trying to do (to collaborators, investors, audience, etc.) just becomes harder at every level (often we&#8217;re forced to rely on examples of existing games, and tough luck if they&#8217;re not really well known). </p><p>Having enough of a shared language that those unfamiliar can use to get an initial grip on things is valuable. As a younger medium, I think games have a lot of design space left to explore compared to stuff like literature or film, and I think a willingness to map things out will help us find foundational conventions, wisdom about what <em>truly </em>works, faster.</p><div><hr></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xPZG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xPZG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 424w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 848w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 1272w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xPZG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png" width="736" height="267" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:267,&quot;width&quot;:736,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44140,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xPZG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 424w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 848w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 1272w, https://substackcdn.com/image/fetch/$s_!xPZG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4d07d3a-9e34-44ef-a966-f0ab4c85caf2_736x267.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6MmQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6MmQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 424w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 848w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 1272w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6MmQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png" width="721" height="244" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:244,&quot;width&quot;:721,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:43587,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6MmQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 424w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 848w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 1272w, https://substackcdn.com/image/fetch/$s_!6MmQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F26b94174-d855-4cc5-8504-e5b294b7c620_721x244.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DSoY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DSoY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 424w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 848w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 1272w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DSoY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png" width="667" height="125" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:125,&quot;width&quot;:667,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16662,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DSoY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 424w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 848w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 1272w, https://substackcdn.com/image/fetch/$s_!DSoY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb0e59eb6-2b41-4284-8122-ec3dcb13188f_667x125.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CfAo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CfAo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 424w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 848w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 1272w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CfAo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png" width="622" height="136" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:136,&quot;width&quot;:622,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17523,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CfAo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 424w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 848w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 1272w, https://substackcdn.com/image/fetch/$s_!CfAo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4e742fd-7c6f-4c74-8215-58d3f5bd4a7f_622x136.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VERx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VERx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 424w, https://substackcdn.com/image/fetch/$s_!VERx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 848w, https://substackcdn.com/image/fetch/$s_!VERx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 1272w, https://substackcdn.com/image/fetch/$s_!VERx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VERx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png" width="728" height="173" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:173,&quot;width&quot;:728,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30485,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VERx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 424w, https://substackcdn.com/image/fetch/$s_!VERx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 848w, https://substackcdn.com/image/fetch/$s_!VERx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 1272w, https://substackcdn.com/image/fetch/$s_!VERx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb98c4aae-33a7-4de4-ba0c-3adfc4f84151_728x173.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-AkC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-AkC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 424w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 848w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 1272w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-AkC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png" width="694" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:694,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26072,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-AkC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 424w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 848w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 1272w, https://substackcdn.com/image/fetch/$s_!-AkC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6107b64e-21db-4168-911a-8bd90acd20bd_694x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>(and many more along these lines)</p><p>I&#8217;m not sure how many of these people actually took time to look at the list of similarities, but they do have a bit of a point: on the surface, the games presented play very differently. This is most of the reason why I don&#8217;t think the categorization is quite a &#8220;subgenre&#8221;. The core idea can evidently be applied to many different gameplay styles, though it does seem to mesh best with puzzle games (in the &#8216;bite-sized puzzle&#8217; sense).</p><p>It does feel to me like other people are able to pick up on the shared heart of these games, given reactions like this:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2xEA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2xEA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 424w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 848w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 1272w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2xEA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png" width="734" height="206" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:206,&quot;width&quot;:734,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:40083,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2xEA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 424w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 848w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 1272w, https://substackcdn.com/image/fetch/$s_!2xEA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F01a9fb11-bf3b-4f9d-97f3-7ae814de6bbc_734x206.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>And people managing to point out other examples that nail it:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m7ay!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m7ay!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 424w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 848w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 1272w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m7ay!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png" width="573" height="100" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:100,&quot;width&quot;:573,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17570,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m7ay!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 424w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 848w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 1272w, https://substackcdn.com/image/fetch/$s_!m7ay!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2362882c-5edc-4cdb-8095-79e7c204d92f_573x100.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>But a wise man (who sleeps on my couch) once said you find what&#8217;s interesting about things by seeing how they <em>differ</em> from other things<em>, </em>rather than pointing out similarities. In that spirit, I did try to point out some games that I think fall just shy of this category and why:</p><blockquote><ul><li><p>Inscryption: Too linear, not enough 'free' exploration, too strategy focused.</p></li><li><p>Cave Story: Too linear, not enough exploration focus, progression is not so heavily based on game knowledge, too action-focused.</p></li><li><p>Paradise Killer: "Puzzle solving" is too straightforward, mostly a collect-a-thon.</p></li><li><p>Return of the Obra Dinn: Does not feature hidden "layers" of content, the method of exploration and discovery does not break much from expectations set at the start of the game.</p></li><li><p>Baba is You: Not particularly lore rich.</p></li><li><p>Stephen's Sausage Roll: Outright "hidden" content is minimal.</p></li><li><p>Undertale: Main game is too linear, "open" exploration elements are minimal.</p></li><li><p>The Stanley Parable: No real puzzle-solving to speak of.</p></li></ul></blockquote><p>Some other games people brought up also felt similar but ultimately separate to me, I&#8217;ll take the opportunity to go in-depth as to why:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ptb3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ptb3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 424w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 848w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 1272w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ptb3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png" width="687" height="198" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:198,&quot;width&quot;:687,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33574,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ptb3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 424w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 848w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 1272w, https://substackcdn.com/image/fetch/$s_!Ptb3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd30d8477-0cb0-40bf-9419-8e2560d3952c_687x198.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Dark Souls titles, while featuring quite a surprising number of traits from the original list, are fairly easy to exclude simply due to their segmentation and linearity. The world <em><strong>as a whole</strong> </em>is never turned into a puzzle for you to solve.</p><p>Elden Ring was admittedly harder to exclude; it <em>does </em>have a well-executed <em><strong>open-ended</strong></em> exploration aspect, and quite a pile of secrets and knowledge to collect. In its case, I think it&#8217;s simply a matter of where the focus lies. Progression in Elden Ring is not solely or even primarily based around <em><strong>knowledge</strong></em>,<em> </em>i.e. investigation, cracking the world&#8217;s puzzle, etc. RPG-style character building and the development of your action-based combat skills play a much larger role; this is ultimately what sets it apart from the original set of examples.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xaYH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xaYH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 424w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 848w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 1272w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xaYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png" width="748" height="207" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:207,&quot;width&quot;:748,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:32405,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xaYH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 424w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 848w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 1272w, https://substackcdn.com/image/fetch/$s_!xaYH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a53430f-ede9-41c3-a2bb-6d64c166d8ad_748x207.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Well said gorillastats. Disco Elysium&#8230; it&#8217;s feels close. But despite all the freedom the player is handed, it&#8217;s all concentrated in how the moment-to-moment gameplay unfolds. In most playthroughs, all the same scenes will occur, even if their exact contents and order might be shuffled around (and give-or-take some optional questlines). And you&#8217;re never really <em>alone </em>in your journey to unravel the game&#8217;s mysteries, thanks to the more-or-less friendly NPCs you&#8217;re always talking to, as well as&#8230; the player character? </p><p>Yeah, that&#8217;s the other glaring thing, <em>you&#8217;re </em>not quite the one doing any puzzle solving, you&#8217;re <em>roleplaying as a character</em> that does so. There is no real <em><strong>systemic </strong></em>overarching environment to be analyzed and conquered, but rather a (skilfully woven) web of fiction the player gradually traces to its inevitable conclusion. That&#8217;s what sets Disco Elysium (and many other &#8220;adventure&#8221; games) apart.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QFML!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QFML!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 424w, https://substackcdn.com/image/fetch/$s_!QFML!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 848w, https://substackcdn.com/image/fetch/$s_!QFML!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 1272w, https://substackcdn.com/image/fetch/$s_!QFML!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QFML!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png" width="725" height="213" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:213,&quot;width&quot;:725,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25641,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QFML!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 424w, https://substackcdn.com/image/fetch/$s_!QFML!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 848w, https://substackcdn.com/image/fetch/$s_!QFML!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 1272w, https://substackcdn.com/image/fetch/$s_!QFML!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21d0233c-fcb6-45b0-9229-e28f5c1fea90_725x213.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Er, nowhere did I claim that games in this category are inherently better or worse than others, there are plenty of games on the &#8220;not&#8221; list that I like more than some out of the 7 original examples I gave. </p><p>Regardless, I wanted to bring up Obra Dinn since I think what distinguishes it is telling. It does seem to check a lot of boxes, so why doesn&#8217;t it fit? I think my response to the previous reply hints at what&#8217;s going on here. While Obra Dinn has something of an overarching system, deciphering it is not where the game&#8217;s challenge lies. All the important rules are freely presented to you fairly early on, and you are left with a very clear set of goals to accomplish. Heck, the game even hands you a comprehensive list of blank fields to be filled in as you go. </p><p>This is in contrast to the original example games, who are <em><strong>unguided</strong></em>;<em><strong> </strong></em>you&#8217;re always expected to fathom yourself not just the world and its history, but <em>the very rules of the game you&#8217;re playing</em>.<em> </em>Each discovery in this realm drastically shifts your perspective and recontextualizes your entire playthrough thus far, and the games are usually structured such that you come to these realizations at an interesting pace. These realizations, discoveries, perspective-shifts, one might even call them&#8230; epiphanies&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4fMg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4fMg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 424w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 848w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 1272w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4fMg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png" width="738" height="218" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/da52068c-64ef-42aa-a164-fbb0b4814774_738x218.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:218,&quot;width&quot;:738,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29822,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4fMg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 424w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 848w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 1272w, https://substackcdn.com/image/fetch/$s_!4fMg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fda52068c-64ef-42aa-a164-fbb0b4814774_738x218.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>So, even I felt Rain World was a bit of an outlier in the original list, and now I think I can put my finger on why. It&#8217;s closer than any of the other examples of &#8220;almost&#8221; games I&#8217;ve presented thus far (obviously, since it managed to sneak onto the original list lol), but there&#8217;s one clear difference I can point to now between it and the other games. Rather than being entirely <strong>bespoke </strong>and <strong>predictable</strong>, its system is partially <em>generative </em>and <em>non-deterministic</em>.</p><p>Let&#8217;s use an example: in Outer Wilds, the developers (and eventually the player) can have complete knowledge of the solar system&#8217;s workings. Barring glitches and player interference, every celestial body will be in a known position at a any given time, every machine in the game will work the same way every time it&#8217;s used, and events and changes can be predicted with perfect accuracy. This means that any knowledge of the system that the player obtains is immediately and clearly applicable and reliable.</p><p>Conversely, in Rain World, a large and critical part of the game&#8217;s overarching &#8220;system&#8221; is its dynamic ecosystem. Animals all have their own AI will behave unpredictably in response to the player, the environment, and other animals. The ecosystem also exists and progresses independent of the player, which means the world and its inhabitants might undergo significant change while you&#8217;re not looking. While there are still rules to discover, significantly more experimentation might be necessary to do so, the knowledge earned is harder to apply reliably, and few things ever become truly 100% predictable.</p><p>Is this difference enough to disqualify rain world? Maybe not, I don&#8217;t think it&#8217;s necessarily satisfying a completely different internal drive, and it does feel <em>very </em>similar to the other examples. Still, there is a clear difference, and I think it might be worth further distinguishing these sorts of &#8220;emergent sim-y&#8221; takes on the core idea for those who can stomach the nuance.</p><div><hr></div><p> Alright, let&#8217;s see if anyone&#8217;s come up with a good, snappy tag for this sort of thing.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AgFC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AgFC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 424w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 848w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 1272w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AgFC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png" width="733" height="178" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:35185,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!AgFC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 424w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 848w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 1272w, https://substackcdn.com/image/fetch/$s_!AgFC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3ae95f2c-eef4-4813-be78-6bbac84d89ef_733x178.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DJ7V!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DJ7V!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 424w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 848w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 1272w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DJ7V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png" width="732" height="156" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:156,&quot;width&quot;:732,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:25333,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DJ7V!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 424w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 848w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 1272w, https://substackcdn.com/image/fetch/$s_!DJ7V!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac48ac0d-2783-4d46-9e87-40b76203d0c2_732x156.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TBtu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TBtu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 424w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 848w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 1272w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TBtu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png" width="743" height="115" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:115,&quot;width&quot;:743,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15700,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TBtu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 424w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 848w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 1272w, https://substackcdn.com/image/fetch/$s_!TBtu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F59b00046-4f13-4eac-9d85-4d825c7637c1_743x115.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eCHL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eCHL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 424w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 848w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 1272w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eCHL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png" width="734" height="122" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2032d162-be22-4a86-9900-fab442e83416_734x122.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:122,&quot;width&quot;:734,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:18068,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eCHL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 424w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 848w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 1272w, https://substackcdn.com/image/fetch/$s_!eCHL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2032d162-be22-4a86-9900-fab442e83416_734x122.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HK7i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HK7i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 424w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 848w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 1272w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HK7i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png" width="736" height="120" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:120,&quot;width&quot;:736,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17135,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HK7i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 424w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 848w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 1272w, https://substackcdn.com/image/fetch/$s_!HK7i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39a8c1c2-8d74-4785-874d-6fa88d25aef6_736x120.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!btBK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!btBK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 424w, https://substackcdn.com/image/fetch/$s_!btBK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 848w, https://substackcdn.com/image/fetch/$s_!btBK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 1272w, https://substackcdn.com/image/fetch/$s_!btBK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!btBK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png" width="741" height="126" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:126,&quot;width&quot;:741,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17565,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!btBK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 424w, https://substackcdn.com/image/fetch/$s_!btBK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 848w, https://substackcdn.com/image/fetch/$s_!btBK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 1272w, https://substackcdn.com/image/fetch/$s_!btBK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd5a20ba8-0ac2-45e3-b69b-3fc3572069b2_741x126.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>I don&#8217;t really think sticking them under a broad umbrella like this is really helpful. For example, there are plenty of titles I and others would happily deem &#8220;adventure games&#8221; that clearly <em>don&#8217;t </em>fall in or even close to the category. Similarly broad labels don&#8217;t fare much better in this regard.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pgMb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pgMb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 424w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 848w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 1272w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pgMb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png" width="738" height="178" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:738,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:33867,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pgMb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 424w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 848w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 1272w, https://substackcdn.com/image/fetch/$s_!pgMb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc758fa8-8ff8-4fe9-bc09-2bd488d3cd1a_738x178.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">omg nightmargin</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4Swv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4Swv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 424w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 848w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 1272w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4Swv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png" width="740" height="122" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/80869819-b0c0-489c-9275-534049c92c69_740x122.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:122,&quot;width&quot;:740,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:15621,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4Swv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 424w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 848w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 1272w, https://substackcdn.com/image/fetch/$s_!4Swv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F80869819-b0c0-489c-9275-534049c92c69_740x122.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7iuf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7iuf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 424w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 848w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 1272w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7iuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png" width="747" height="153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f2affe2-8785-4433-8914-1083940bf58f_747x153.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:153,&quot;width&quot;:747,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23006,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7iuf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 424w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 848w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 1272w, https://substackcdn.com/image/fetch/$s_!7iuf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f2affe2-8785-4433-8914-1083940bf58f_747x153.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!q--O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!q--O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 424w, https://substackcdn.com/image/fetch/$s_!q--O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 848w, https://substackcdn.com/image/fetch/$s_!q--O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 1272w, https://substackcdn.com/image/fetch/$s_!q--O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!q--O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png" width="733" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/daef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53885,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!q--O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 424w, https://substackcdn.com/image/fetch/$s_!q--O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 848w, https://substackcdn.com/image/fetch/$s_!q--O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 1272w, https://substackcdn.com/image/fetch/$s_!q--O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdaef0279-0a14-4ddc-b738-7fb1285efcb3_733x451.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I had some, ah, choice words for this one:</p><blockquote><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1m2g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1m2g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 424w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 848w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 1272w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1m2g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png" width="737" height="150" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/adf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:150,&quot;width&quot;:737,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28249,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1m2g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 424w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 848w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 1272w, https://substackcdn.com/image/fetch/$s_!1m2g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fadf6b47b-2460-4c67-8077-f0e562f195bf_737x150.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5Paf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5Paf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 424w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 848w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 1272w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5Paf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png" width="735" height="187" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:187,&quot;width&quot;:735,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:30876,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!5Paf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 424w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 848w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 1272w, https://substackcdn.com/image/fetch/$s_!5Paf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffbf1cd5d-7f9e-4a65-be37-2ede819030e7_735x187.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div></blockquote><p>Not much more to say, though to expand on the first comment, the reason I think an overreliance on genre terms based on existing titles is corrosive (doubly so for genre terms like this which are based on existing genre terms of the sort) is that it tends to obfuscate what we actually care about in those titles and makes it unnecessarily harder to communicate with those who might be less familiar with those titles. Some mentioned the term &#8220;tunicwild&#8221;, the same criticism applies to that.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!g_Hr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!g_Hr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 424w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 848w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 1272w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!g_Hr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png" width="737" height="147" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:147,&quot;width&quot;:737,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:22714,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!g_Hr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 424w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 848w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 1272w, https://substackcdn.com/image/fetch/$s_!g_Hr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc4d0c8e2-872b-40f8-81c8-e31ebf486791_737x147.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QBWR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QBWR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 424w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 848w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 1272w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QBWR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png" width="741" height="182" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:182,&quot;width&quot;:741,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28914,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QBWR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 424w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 848w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 1272w, https://substackcdn.com/image/fetch/$s_!QBWR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9e78e647-2aa4-4552-9fa9-bc79b5f74f3a_741x182.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XudO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XudO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 424w, https://substackcdn.com/image/fetch/$s_!XudO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 848w, https://substackcdn.com/image/fetch/$s_!XudO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 1272w, https://substackcdn.com/image/fetch/$s_!XudO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XudO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png" width="734" height="147" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:147,&quot;width&quot;:734,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:27414,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XudO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 424w, https://substackcdn.com/image/fetch/$s_!XudO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 848w, https://substackcdn.com/image/fetch/$s_!XudO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 1272w, https://substackcdn.com/image/fetch/$s_!XudO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F642b1613-ec24-4f1d-a65a-8baa4c3965c6_734x147.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QQ70!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QQ70!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 424w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 848w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 1272w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QQ70!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png" width="733" height="114" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c25258b8-8594-4edb-8075-a09a0518f66f_733x114.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:114,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:16538,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!QQ70!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 424w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 848w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 1272w, https://substackcdn.com/image/fetch/$s_!QQ70!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc25258b8-8594-4edb-8075-a09a0518f66f_733x114.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JjJe!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JjJe!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 424w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 848w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 1272w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JjJe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png" width="733" height="145" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:145,&quot;width&quot;:733,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:24595,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JjJe!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 424w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 848w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 1272w, https://substackcdn.com/image/fetch/$s_!JjJe!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F35818e89-8406-416e-aff9-cb0097a1c03f_733x145.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mzk3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mzk3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 424w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 848w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 1272w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mzk3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png" width="738" height="119" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:119,&quot;width&quot;:738,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13143,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mzk3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 424w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 848w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 1272w, https://substackcdn.com/image/fetch/$s_!mzk3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcb9f21aa-cd9b-438c-b765-1c90a659c8ea_738x119.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fQCr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fQCr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 424w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 848w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 1272w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fQCr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png" width="742" height="178" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:178,&quot;width&quot;:742,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:29420,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fQCr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 424w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 848w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 1272w, https://substackcdn.com/image/fetch/$s_!fQCr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5f7f65b8-2b01-4d9d-8daf-8cfe43febc70_742x178.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PD81!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PD81!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 424w, https://substackcdn.com/image/fetch/$s_!PD81!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 848w, https://substackcdn.com/image/fetch/$s_!PD81!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 1272w, https://substackcdn.com/image/fetch/$s_!PD81!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PD81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png" width="753" height="124" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:124,&quot;width&quot;:753,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:12335,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!PD81!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 424w, https://substackcdn.com/image/fetch/$s_!PD81!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 848w, https://substackcdn.com/image/fetch/$s_!PD81!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 1272w, https://substackcdn.com/image/fetch/$s_!PD81!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd7fa4e19-8f03-447c-8d7a-255a5e7588e3_753x124.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Now we&#8217;re talking. I think all these monikers do a good job pointing at the specific thing that makes these games interesting. But as we saw in the Obra Dinn counterexample, &#8220;layers&#8221; is not quite at the <em>core </em>of this feeling. Can we do better?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!U6lM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!U6lM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 424w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 848w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 1272w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!U6lM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png" width="734" height="296" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:296,&quot;width&quot;:734,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:86893,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!U6lM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 424w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 848w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 1272w, https://substackcdn.com/image/fetch/$s_!U6lM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcbf68850-5f78-42ce-8b93-7b4f6af2b978_734x296.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!bdEc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!bdEc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 424w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 848w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 1272w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!bdEc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png" width="744" height="338" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:338,&quot;width&quot;:744,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91798,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!bdEc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 424w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 848w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 1272w, https://substackcdn.com/image/fetch/$s_!bdEc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa2f7f452-7f3f-41f5-87d7-276c66efd60b_744x338.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dUwv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dUwv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 424w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 848w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 1272w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dUwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png" width="748" height="408" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/52603f7e-4411-47d5-a98c-423edde112b9_748x408.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:408,&quot;width&quot;:748,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:72019,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dUwv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 424w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 848w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 1272w, https://substackcdn.com/image/fetch/$s_!dUwv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F52603f7e-4411-47d5-a98c-423edde112b9_748x408.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>I&#8217;m pleasantly surprised people kept recommending that video, since it seems to frame &#8216;KBUs&#8217; as just a mechanic that some games have, rather than any sort of genre tag. It&#8217;s definitely on the right track in that regard, and, as we saw, knowledge-based progression is crucial to the category definition. Even the Hypnospace designer seems to agree. Unfortunately, this term seems too narrow, and it&#8217;s pointing to a mechanic that many games have, not just the ones we&#8217;re trying to delineate.</p><p>Consciously or not though, it seems Jay might have independently hit upon what we&#8217;re looking for in his reply&#8230;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ixN2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ixN2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 424w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 848w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 1272w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ixN2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png" width="750" height="143" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:143,&quot;width&quot;:750,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19293,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ixN2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 424w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 848w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 1272w, https://substackcdn.com/image/fetch/$s_!ixN2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fba5ed660-3754-418f-8e33-a247b6c4e168_750x143.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E3LC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E3LC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 424w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 848w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 1272w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E3LC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png" width="754" height="201" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:201,&quot;width&quot;:754,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42773,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!E3LC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 424w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 848w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 1272w, https://substackcdn.com/image/fetch/$s_!E3LC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15dd3ddd-228d-46ea-96df-45dd5b5898a1_754x201.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!adni!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!adni!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 424w, https://substackcdn.com/image/fetch/$s_!adni!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 848w, https://substackcdn.com/image/fetch/$s_!adni!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 1272w, https://substackcdn.com/image/fetch/$s_!adni!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!adni!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png" width="874" height="413" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:413,&quot;width&quot;:874,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:117492,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!adni!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 424w, https://substackcdn.com/image/fetch/$s_!adni!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 848w, https://substackcdn.com/image/fetch/$s_!adni!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 1272w, https://substackcdn.com/image/fetch/$s_!adni!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F27148da5-6c8a-4514-8e68-9a4c3c2400da_874x413.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption"><a href="https://www.gamedeveloper.com/design/-i-the-witness-i-modeling-epiphany">https://www.gamedeveloper.com/design/-i-the-witness-i-modeling-epiphany</a></figcaption></figure></div><p>This feeling. These might not be the only sorts of games that can provide it, but I can&#8217;t think of any type of game that provides a stronger or purer form of it than this one. If one lacks time to get into the nuance, I think &#8216;epiphany-driven&#8217; is great shorthand. </p><p>Good job, team!</p><div><hr></div><p>So&#8230; was there anything else? Well, some people took my original 7 examples as being <em>comprehensive, </em>which is pretty laughable. Therefore, I&#8217;d be remiss not to offer some game recs! Let&#8217;s see what the public has to say:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FZo1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FZo1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FZo1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png" width="1200" height="1200" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1200,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:271828,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FZo1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 424w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 848w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 1272w, https://substackcdn.com/image/fetch/$s_!FZo1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F636af2e8-6b4d-4c15-b41a-6654c9bf1b69_1200x1200.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Yes, yes, ok!</em> I can&#8217;t <em>believe </em>I forgot Tunic when I was making the original image. It might be a good bit more action-focused than the other titles, but it definitely fits the bill.</p><p>Regarding Fez, it&#8217;s been a while since I last played it so I wasn&#8217;t sure how closely it fit. Still, I wouldn&#8217;t expect anyone who likes this sort of stuff to have a bad time with it, so go check it out!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!z10r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!z10r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 424w, https://substackcdn.com/image/fetch/$s_!z10r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 848w, https://substackcdn.com/image/fetch/$s_!z10r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 1272w, https://substackcdn.com/image/fetch/$s_!z10r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!z10r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png" width="750" height="161" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a4f48800-f161-4198-b494-363330b2a57a_750x161.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:161,&quot;width&quot;:750,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26858,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!z10r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 424w, https://substackcdn.com/image/fetch/$s_!z10r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 848w, https://substackcdn.com/image/fetch/$s_!z10r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 1272w, https://substackcdn.com/image/fetch/$s_!z10r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa4f48800-f161-4198-b494-363330b2a57a_750x161.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Seconded. Solid recommendation. It&#8217;s similar to Baba is You in that it checks pretty much all the boxes but doesn&#8217;t quite have much in the way of lore for you to uncover. That aspect of things adds quite significantly to the feel and character of an epiphany-driven game, but at this point I won&#8217;t go quite so far as to call it absolutely essential.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!05-I!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!05-I!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 424w, https://substackcdn.com/image/fetch/$s_!05-I!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 848w, https://substackcdn.com/image/fetch/$s_!05-I!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 1272w, https://substackcdn.com/image/fetch/$s_!05-I!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!05-I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png" width="746" height="183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:183,&quot;width&quot;:746,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!05-I!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 424w, https://substackcdn.com/image/fetch/$s_!05-I!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 848w, https://substackcdn.com/image/fetch/$s_!05-I!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 1272w, https://substackcdn.com/image/fetch/$s_!05-I!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F730327ef-b441-48f0-a739-f7a5fa5549f3_746x183.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Neither of these games quite land in the epiphany-driven bucket imo, but it&#8217;s interesting that Subnautica came up in my discussion of the topic with friends. If you want a not-quite-epiphany-driven game that leans more in a survival-sandbox direction, it might be the one for you.</p><div><hr></div><p>Also, here are all the games that look interesting from the trailers but which I haven&#8217;t otherwise played or heard much about. </p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4ogo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4ogo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 424w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 848w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 1272w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4ogo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png" width="745" height="180" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/10b95380-9183-47ce-8e00-e996a95173f3_745x180.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:180,&quot;width&quot;:745,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17988,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4ogo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 424w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 848w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 1272w, https://substackcdn.com/image/fetch/$s_!4ogo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F10b95380-9183-47ce-8e00-e996a95173f3_745x180.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HfkI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HfkI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 424w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 848w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 1272w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HfkI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png" width="740" height="184" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:184,&quot;width&quot;:740,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:26344,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!HfkI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 424w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 848w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 1272w, https://substackcdn.com/image/fetch/$s_!HfkI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff1633bc7-2ec0-4cb4-8222-0c4ff4163477_740x184.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">I did play Monster&#8217;s Expedition. Not a huge fan, maybe I should give it another shot though.</figcaption></figure></div><p>That&#8217;s all, but if you have recommendations of your own, comment below!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://blog.massimogauthier.com/subscribe?"><span>Subscribe now</span></a></p>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-programmers: Entities! Components! ...System?]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-c31</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-c31</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Fri, 24 May 2024 11:56:04 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/584b37ca-55a9-49f9-8303-271e12091811_589x958.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non-901">&lt;Previous post</a> | </em><a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8">Next post&gt;</a></p><div><hr></div><p>At this point, I&#8217;ve got all my tools set up; you might expect me to start talking about drawing stuff to the screen, or collecting the player&#8217;s input. But I already made my test app! I know I can do all that! I wanted to kick off the <em>real </em>engine project by building one of the many systems that would&#8217;ve been too much work for a test app, and what better place to start than the engine&#8217;s beating heart: the Entity system!</p><h2>Do I know what this is?</h2><p>Maybe. If you&#8217;ve ever used an engine like Unity or Unreal before, you&#8217;ll be familiar with &#8216;Entities&#8217; (a.k.a. &#8216;GameObjects&#8217; or &#8216;Actors&#8217;) in this sense. It&#8217;s an extremely common design pattern that many game engines use to organize and represent almost everything in the game world. My own system takes inspiration from those, while mixing in some ideas from Game Maker. I&#8217;ll tell you exactly how it works later, but before we talk about the &#8220;how&#8221;&#8230;</p><h2>Why do this?</h2><p>Let&#8217;s talk a bit about software architecture. There are a great many ways to think about it, but in this case it&#8217;s helpful to imagine it as a frame, a scaffold. What I&#8217;m doing here is building a core part of the thing that will make it easy to gradually construct a game by adding and tweaking parts while keeping the overall program smooth and performant.</p><p>Philosophies when it comes to this stuff are almost as numerous as the arguments surrounding them. To give you an idea of what I mean, here are a few &#8216;programming paradigms&#8217; that one can follow:</p><ul><li><p><strong>Imperative and Declarative Programming</strong>: These are sort of ur-paradigms, and most other paradigms will fall under either umbrella:</p><ul><li><p>Imperative programming centers around the idea of <em>telling </em>the computer what to do, usually as a list of instructions, which, as we saw in the previous post, is pretty close to how things work under the hood. C is the classic example of an imperative language.</p></li><li><p>Declarative programming is a bit stranger; the idea is that you&#8217;re <em>describing</em>, very precisely, your program&#8217;s problem domain, in the same way that one would &#8220;declare&#8221; that 1+1=2. Instead of incanting &#8220;do this, then this, then that!&#8221;, you incant &#8220;given this, it is so!&#8221;. &#8220;Running&#8221; your program is then just a matter of solving the equation with the given parameters. This is closer to pure mathematics than engineering, and this style tends to be a significantly less popular, but some declarative ideas have been enormously influential, even for imperative work. Lisp is the classic example of a declarative language.</p></li></ul></li><li><p><strong>Object-Oriented</strong> <strong>Programming (OOP)</strong>: An incredibly popular imperative style. Due to how, er, <em>storied </em>its history is, it&#8217;s a bit difficult to nail down exactly how people use this term nowadays, but the basic idea is that your code is divided up into &#8216;objects&#8217;. Each object has data, as well as &#8216;methods&#8217; (little bits of code that can be called to tell the object to do something). There&#8217;s a lot of neat stuff you can do with objects, but OOP has been criticized for encouraging programmers to come up with complicated object structures when a simple list of instructions would do fine. Java, C#, C++, Python, and many more popular languages are considered Object-Oriented.</p></li><li><p><strong>Functional Programming</strong>: A style of declarative programming that has seen some (relative) success. The style is based around <strong>functions</strong>, specifically &#8216;pure&#8217; functions. A function is just a bit of code that takes an input and produces an output, but the idea of a &#8216;pure&#8217; function is that it doesn&#8217;t &#8216;remember&#8217; anything, it can&#8217;t read or write to any memory outside of itself. This guarantees that the function will <em>always</em> produce the same output if given the same input, and that it won&#8217;t silently affect any part of my program without my knowledge. A <em>purely </em>functional style constructs a whole program entirely out of pure functions, a very declarative way of doing things, but pure functions can still be very valuable as part of an imperative program and many ideas from Functional programming have spread all over the place. Haskell is probably the most well-known functional language.</p></li><li><p><strong>Data-Oriented Programming </strong>(a.k.a. Data-Oriented Design, DOD): An imperative philosophy that has gained popularity recently in response to perceived failures of the OOP style. The Data-Oriented philosophy encourages programmers to think more about hardware and memory (see the previous post for more details about this), and to envision their programs as machines purpose-built for funneling and processing large amounts of data in an efficient manner. Jai and ODIN are very much being built under this paradigm. To give a concrete example of DOD, say I&#8217;m making my little game with bouncy balls and whatnot:</p><ul><li><p>If I were doing things OOP-style, I might conjure up a &#8220;ball&#8221; object, give it all the data and behaviors a ball would need, then stick a new one wherever whenever I needed it. When I want all the balls to do something, I&#8217;d define that behavior on the object, then go looking for each of them and tell them &#8220;do this thing you know how to do&#8221;.</p></li><li><p>If I were thinking of things from a DOD perspective, I&#8217;d say: &#8220;I&#8217;m gonna need about 100 bouncy balls!&#8221;. I&#8217;d figure out the exact way to lay out all the data about 100 balls would need, and bundle it in a way that makes it easy for me <em>and </em>the CPU to access. When I wanted the balls to do something, I&#8217;d make a big ol&#8217; &#8220;process_balls&#8221; function that would churn through all that data and make it behave like about 100 bouncy balls.</p></li></ul></li></ul><p>Personally, I always try to do what makes sense for the task at hand, and my Entity system is designed to offer me the flexibility to do so. As the core around which most game features will be built, this is, uh, a pretty important thing for it to have.</p><h2>And now, the how</h2><p>To understand the reasoning behind the design of my engine&#8217;s Entity system, let&#8217;s take a look at how it&#8217;s design compares to the way I&#8217;d typically do things in Game Maker, with the help of some familiar faces from ANTONBLAST!</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BQls!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BQls!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 424w, https://substackcdn.com/image/fetch/$s_!BQls!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 848w, https://substackcdn.com/image/fetch/$s_!BQls!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 1272w, https://substackcdn.com/image/fetch/$s_!BQls!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BQls!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png" width="264" height="225" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2058e118-2972-467d-a37e-9ac53fd21265_264x225.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:225,&quot;width&quot;:264,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1379,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BQls!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 424w, https://substackcdn.com/image/fetch/$s_!BQls!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 848w, https://substackcdn.com/image/fetch/$s_!BQls!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 1272w, https://substackcdn.com/image/fetch/$s_!BQls!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2058e118-2972-467d-a37e-9ac53fd21265_264x225.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">hi pippo</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_Ia1!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_Ia1!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 424w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 848w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 1272w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_Ia1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png" width="271" height="257.26933333333335" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:356,&quot;width&quot;:375,&quot;resizeWidth&quot;:271,&quot;bytes&quot;:2450,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_Ia1!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 424w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 848w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 1272w, https://substackcdn.com/image/fetch/$s_!_Ia1!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fec086659-598b-4bc9-b2cf-7d12bf21a476_375x356.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">It&#8217;s ballbuster!</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2EKj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2EKj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 424w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 848w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 1272w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2EKj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png" width="284" height="243.24663677130044" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:382,&quot;width&quot;:446,&quot;resizeWidth&quot;:284,&quot;bytes&quot;:3413,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2EKj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 424w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 848w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 1272w, https://substackcdn.com/image/fetch/$s_!2EKj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8bdd81f5-8617-4ad4-a793-fad674fe41fc_446x382.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Mosquito. His true name is under strict NDA. Which is good, because I forgot what it was.</figcaption></figure></div><p>GM tends to push the user into an OOP way of doing things. You create &#8220;Objects&#8221;, and each has events that get triggered when something happens (my own system uses something very similar in this regard, so we&#8217;ll talk about it later). You&#8217;re also encouraged to use a very OOP technique for code reuse: Inheritance.</p><p>How a paradigm handles code reuse is core to its identity, one might even say its in a sense what defines a paradigm. Having to repeat yourself is time-consuming and tedious, so programmers are always finding ways to avoid it. </p><p>A classic example is functions themselves. I described them as bits of code that take an input and produce an output, but their real power is that you can &#8216;call&#8217; them from anywhere, over and over, with just one line of code per call. If I have a complicated bit of behavior that I need to use often, I can put it into a function, then just call that function. If it takes no input, its practically as if I just copy-pasted that bit of code all over the place (but I can change every instance of it just by changing the function!). If it <em>does </em>take input, even better! I can make the function do something slightly different whenever I use it just by changing its input.</p><p>So, inheritance, what is it? Basically, it&#8217;s a way for objects to share functionality amongst themselves by &#8220;inheriting&#8221; it from a parent object. Confused? Let&#8217;s take the example of our three buddies<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>: </p><ul><li><p>Pippo is a simple enemy that walks around. The player can bounce on him to knock him over, and can also hit him to send him flying.</p></li><li><p>Ballbuster is a more dangerous enemy that also walks around. When he sees the player, he&#8217;ll charge at him. Like Pippo, he&#8217;ll go flying when the player hits him.</p></li><li><p>Mosquito doesn&#8217;t do much, just floats in place, but the player can also hit him and bounce off of him.</p></li></ul><p>You&#8217;ll notice that these are all enemies, and they all have behaviors in common. Instead of rewriting those common behaviors three times, I can put all the methods and data needed for them into a parent &#8220;Enemy&#8221; object, and have objects for each of the three enemies that inherit from it (any behavior specific to an individual enemy gets put in that individual enemy&#8217;s object).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dUua!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dUua!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 424w, https://substackcdn.com/image/fetch/$s_!dUua!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 848w, https://substackcdn.com/image/fetch/$s_!dUua!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 1272w, https://substackcdn.com/image/fetch/$s_!dUua!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dUua!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png" width="490" height="466.53256704980845" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:497,&quot;width&quot;:522,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:17326,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dUua!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 424w, https://substackcdn.com/image/fetch/$s_!dUua!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 848w, https://substackcdn.com/image/fetch/$s_!dUua!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 1272w, https://substackcdn.com/image/fetch/$s_!dUua!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5ec2bc-17c8-4fb8-bf1f-da3d3ab91ca3_522x497.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>But wait! Pippo and Ballbuster walk around, while the mosquito just floats in place! Where do I put the walking behavior? Well, inheritance trees can go more than one layer deep, so we can do something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kadY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kadY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 424w, https://substackcdn.com/image/fetch/$s_!kadY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 848w, https://substackcdn.com/image/fetch/$s_!kadY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 1272w, https://substackcdn.com/image/fetch/$s_!kadY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kadY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png" width="496" height="454.40506329113924" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/11556251-7715-4810-a834-380d42276071_632x579.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:579,&quot;width&quot;:632,&quot;resizeWidth&quot;:496,&quot;bytes&quot;:25839,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kadY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 424w, https://substackcdn.com/image/fetch/$s_!kadY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 848w, https://substackcdn.com/image/fetch/$s_!kadY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 1272w, https://substackcdn.com/image/fetch/$s_!kadY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F11556251-7715-4810-a834-380d42276071_632x579.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>And now, say I want as version of Pippo that&#8217;s mostly identical, but who sheds feathers when he gets hit? Instead of copying Pippo somewhere, I can just keep extending things!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2ozz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2ozz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 424w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 848w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 1272w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2ozz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png" width="430" height="474.935691318328" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:687,&quot;width&quot;:622,&quot;resizeWidth&quot;:430,&quot;bytes&quot;:29603,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2ozz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 424w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 848w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 1272w, https://substackcdn.com/image/fetch/$s_!2ozz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc7eb9a3d-0a16-40e1-815c-c112cde22fa1_622x687.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>As you can see, objects and inheritance trees can be pretty powerful, and a natural way of modeling game mechanics like enemies, but as a project&#8217;s size and complexity starts to grow, they can run into some problems. Take this guy, for example:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WF-z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WF-z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 424w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 848w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 1272w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WF-z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png" width="323" height="325.42857142857144" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:402,&quot;width&quot;:399,&quot;resizeWidth&quot;:323,&quot;bytes&quot;:3628,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WF-z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 424w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 848w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 1272w, https://substackcdn.com/image/fetch/$s_!WF-z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F627c4456-fd2b-4bd2-adc7-e0d161f9604e_399x402.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>He&#8217;s a big totem guy that the player can stand on top of. He spits stuff. Nice guy. Now, question for you, is this guy a <em>block</em>, or an <em>enemy</em>? Stuff will collide with him, just like a block, but he also attacks the player, and can be stunned, just like an enemy. You can&#8217;t inherit from multiple parents (for complicated technical reasons), so you kind of have to pick one.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OtEG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OtEG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 424w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 848w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 1272w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OtEG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png" width="620" height="345.91939546599497" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:443,&quot;width&quot;:794,&quot;resizeWidth&quot;:620,&quot;bytes&quot;:19996,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OtEG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 424w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 848w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 1272w, https://substackcdn.com/image/fetch/$s_!OtEG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0153620-cc37-445e-b2bf-a27cb84623f6_794x443.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Usually, in cases like these, I have to pick the most relevant parent, and cobble together the other behavior as best I can. The other option is to rethink the inheritance tree structure, but rearranging the tree can be time-consuming and annoying, and will often cause problems for other objects. </p><p>Here are some other issues that crop up with inheritance:</p><ul><li><p>Say I have 10 objects. A handful of them want behavior A, a slightly different handful want behavior B, and another handful also want behavior C. Even if I&#8217;m aware of all this ahead of time, which I&#8217;m likely <em>not</em>, there isn&#8217;t an obvious way to make an inheritance tree that sorts the behaviors in a neat way. Making a parent with all three behaviors is doable, but would require shutting off certain behaviors in many of the children, which is annoying to do and keep track of, especially if it has to be done after-the-fact.</p></li><li><p>If a bunch of objects all want behaviors A, B, and C, but a few only want behaviors A and B, well, tough luck, they&#8217;re also getting C. I can turn it off, but this often still introduces complexity and performance overhead to objects for behaviors they aren&#8217;t even using.</p></li><li><p>Methods on parents can be inherited or &#8216;overriden&#8217; by child objects, which involves the child either replacing or adding on to what a method does. This is an important and useful feature, but it introduces performance overhead related to having to retrieve all these parent and child methods while the game is running.</p></li><li><p>Once inheritance trees start to reach a certain depth they get&#8230; annoying. Did I put that behavior in this object or that one? Should this new thing be a child of this or should I put it further down? I need to do all these things in order on this object but skip step 3 on this other object, do I split steps 1 and 2 into their own method? Oops, it&#8217;s now 3 months later and I don&#8217;t remember which part of the sequence is in which method, <em>fun</em>&#8230;</p></li></ul><p>Ok, so&#8230; what, then? This design pattern, built directly into almost every major modern language as a first class feature, used by most software out there, present in nearly every tutorial, is it just dumb and bad?</p><p>Uh, yeah, kinda.</p><p>I&#8217;m not the only one who thinks this, a lot of engineers have been distancing themselves from the excesses of OOP over the past decade and more, despite its ubiquity. But what&#8217;s the alternative? Personally, I&#8217;m not quite ready to jump fully off the OOP train, but if I&#8217;m gonna be avoiding inheritance for the most part, how am I gonna handle code reuse? This is where a compositional approach comes in.</p><h2>Go on then</h2><p>Let&#8217;s take a look, finally, at how my Entity system works:</p><ul><li><p>Everything in the world is represented by an <strong>Entity</strong>. An Entity can represent anything: the player, a tree, an enemy, the sky, etc.</p></li><li><p>On their own, Entities do nothing, <em>are </em>nothing. Their existence is defined by the set of <strong>Components </strong>attached to them.</p></li><li><p>Components are little bundles of data that can be combined together modularly to form an entity. Components can be many different things. They might be, for example:</p><ul><li><p>A set of coordinates that tells you where an Entity is in the world.</p></li><li><p>A set of physics parameters, like gravity and friction, which can be used to move an Entity around.</p></li><li><p>A set of rendering parameters, used to render an animated sprite.</p></li></ul></li><li><p>So, to give a complete example, say I wanted to make an Entity that represented a gremlin enemy. I&#8217;d attach a position and movement Component, so that I can move it around; a collider Component, so that it can collide with things; a hitbox Component, so that it can hit things with attacks; and I&#8217;d make a special new &#8220;gremlin&#8221; Component that would be used for anything specific to the gremlin.</p></li><li><p>In addition to all that, Components can react to a standardized set of <strong>Events, </strong>just like Game Maker objects.<strong> </strong>The most common Events would be `init`, which is triggered just for a specific Component when it is newly added to an Entity, and `update`, which is triggered once per frame<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>. Put simply, I can define behavior for each specific component that will trigger in response to these events.</p></li></ul><p>For the most part, this preserves a lot of what I like about Game Maker&#8217;s system while getting around the pitfalls of inheritance. Rather than bundling behaviors into parents, behaviors can be modularized into their own component and freely included or excluded depending on what a specific Entity needs. Take the totem guy from earlier: instead of agonizing over whether he should be an enemy or a block, I can just slap a bounce component and a block collision component on him and call it a day!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a></p><p>The way the component system is designed under the hood also has performance benefits. Rather than going to each entity, scattered around in memory willy-nilly, and tracking down their methods, every component of a given type is kept in one block which the engine processes all at once. Since components are usually pretty small, processing them all in one chunk like this can be extremely quick. &#8220;Entities&#8221;, under the hood, are actually just like little address books that components sometimes use to get related components from a different chunk. Neat!</p><h2>Hmm&#8230; still doesn&#8217;t seem very DOD</h2><p>Well&#8230; yeah. If you were paying attention to the bouncy ball example, I&#8217;ll admit this isn&#8217;t <em>quite </em>that. I&#8217;m making a bit of a compromise&#8230; but hear me out. A lot of my work days look like me:</p><ol><li><p>Getting a design for a new enemy, or block, or level mechanism.</p></li><li><p>Spinning up a new object that inherits from the relevant parent.</p></li><li><p>Writing up any new behaviors that object might need.</p></li><li><p>Revising and polishing that specific object.</p></li></ol><p>And I haven&#8217;t quite found a way to map that workflow, in my head, to something that doesn&#8217;t end up looking at least a little bit OOP. The Entity system, combined with a dash of code generation and some (perfectly kosher) syntactic tricks, allows me to quickly spin up work environments that feel just like what I&#8217;m used to, but better.</p><p>But, and here&#8217;s the beauty of making my own engine, I don&#8217;t <em>have </em>to use the entity system for everything. If a new mechanic or system seems like it would benefit from a less OOP-like approach, there&#8217;s nothing stopping me from taking it in that case. So&#8230; we&#8217;ll see. Maybe, at the end of a long project with this engine, I&#8217;ll find that I hardly needed any Entities at all. But for now, I&#8217;d like to have some familiar ground.</p><h2>Anything else?</h2><p>Not really, though I&#8217;d be remiss to mention one last thing. You might have heard of &#8220;Entity Component System&#8221; architectures, or ECS. Despite the name, my thing is&#8230; not that. Rather than being Event-driven like mine, entities in an ECS system use things called &#8220;Systems&#8221; (brilliant nomenclature, I know), which are these things which identify entities which have certain <em>sets </em>of components on them and run code on them. It&#8217;s not a bad idea, but it&#8217;s never struck me as quite how I want things done.</p><div><hr></div><p>At the moment, the Entity system is mostly done, but without other systems it&#8217;s like a heart with no legs. Or arms. Or pulse.</p><p>&#8230;</p><p>There are a few big things I need to get done before I really stress test it, the first of which we&#8217;ll be seeing next week: The Game Loop.</p><p>See you then! </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non-901">&lt;Previous post</a> | </em><a href="https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-bd8">Next post&gt;</a></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Fun fact: The explanation that follows is real! This is actually how these enemies were planned out and built to work in the game&#8217;s actual codebase. It&#8217;s obviously a little simplified though.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>We&#8217;ll talk more about the &#8216;game loop&#8217; at a late date, but I&#8217;ll give a quick explainer here if you don&#8217;t know what I mean by &#8216;frames&#8217;: Like film, video games run at certain frame rate, often 60 frames per second. For every frame, the game will update the state of the world (e.g. moving objects will move a tiny bit, animations will go to their next frame, etc.) then render the result onto your screen. At a high enough frame rate, this creates the illusion of a smoothly moving world.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>You might be wondering: some components (like, say, a position component) are gonna get shared around <em>a lot</em>, won&#8217;t that get tedious? But hey, there&#8217;s nothing stopping me from making functions that add a bunch of components at once, bundling them together, sort of like a pseudo-parent. I can even have components automatically add other components that they require in order to work, further cutting down on boilerplate code. The key here is that I&#8217;m not <em>forced </em>to keep behaviors in one bundle. If, in certain cases, I want to split them up, or make a different bundle, it&#8217;s trivial to do so.</p></div></div>]]></content:encoded></item><item><title><![CDATA[Game Engine Dev, Explained for Non-Programmers: Choosing the Right Tools]]></title><description><![CDATA[This series can be read out of order, but here are some navigation links for your convenience:]]></description><link>https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-901</link><guid isPermaLink="false">https://blog.massimogauthier.com/p/game-engine-dev-explained-for-non-901</guid><dc:creator><![CDATA[Massimo Gauthier]]></dc:creator><pubDate>Fri, 17 May 2024 03:04:55 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/792cf3a5-ad89-4e01-b266-de0ff6aaad31_840x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>This series can be read out of order, but here are some navigation links for your convenience:</em></p><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non-c31">Next Post&gt;</a></em></p><div><hr></div><p>So, I know I&#8217;ve made a big deal out of starting from scratch, but nobody actually does that ever for anything<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-1" href="#footnote-1" target="_self">1</a>. In my case, there&#8217;s a whole bundle of tools I&#8217;ll be relying on third-party software for, but to even get started, I&#8217;ll need to decide on <strong>two </strong>things:</p><ul><li><p>A programming language</p></li><li><p>A game development framework</p></li></ul><h2>What is a programming language, anyway?</h2><p><em>You can&#8217;t just ask me that! </em>Dear reader, to truly answer such a question I would be forced to do you a terrible harm! That is, give you a <em>computer science</em> lesson! No, that wouldn&#8217;t do, it simply wouldn&#8217;t. But&#8230; ah, needs must. Here&#8217;s what we&#8217;ll do: I&#8217;ll give you a unique, very special computer science lesson. It will be so special by being incredibly, magnificently brief! I guarantee, you will learn very little. It&#8217;s not ideal, I know, but it will surely be a mercy compared to the alternative. Now then&#8230;</p><div><hr></div><p>What is a programming language? Put simply, it&#8217;s a set of <em>logically consistent </em>rules for writing text<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-2" href="#footnote-2" target="_self">2</a>, called a program, which can be turned into instructions that your computer can understand.</p><p>You might have heard that, fundamentally, your computer only deals in 1s and 0s, but how can it ever read text then? Well, inside pretty much any computer is a device called a Central Processing Unit. In (grossly oversimplified) essence, a CPU is a little machine that takes in and puts out numbers using electrical signals. Each is built with a big set of little tasks<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-3" href="#footnote-3" target="_self">3</a> they can do, called instructions, and each instruction has its own little number to represent it. A program is basically a long list of those little numbers that the CPU reads in order. It&#8217;s even possible to write out that list of instructions directly using something called an assembly language, but this incredibly tedious and difficult, even for relatively simple programs.</p><p>With that in mind, programming languages can be grouped broadly into 2 buckets:</p><ul><li><p>Compiled languages: The more straightforward approach. Compiled languages use a program called a <strong>compiler</strong>, which knows the rules of the language, to read the text you wrote and turn it into a list of instructions for your CPU. You can then run the &#8220;compiled&#8221; program on its own, whenever you want.</p></li><li><p>Interpreted languages: Instead of turning your text into little numbers ahead of time, interpreted languages use a program called an <strong>interpreter</strong>,<strong> </strong>which runs alongside your program, and reads the text to figure out what instructions to give the CPU <em>as your program is running</em>. Interpreted languages tend to be more flexible, since, unlike a compiler, an interpreter doesn&#8217;t need to know what to tell the CPU way ahead of time and can figure things out on the fly. Unfortunately though, this means programs written in interpreted languages are significantly slower, since figuring things out on the fly takes time.</p></li></ul><p>Coming back to my own project: my interest in developing my own engine took serious shape about year ago, when I started more closely following the development of Jai (Jonathan Blow&#8217;s new programming language that he&#8217;s been working on since 2014). Its philosophy and design goals were fascinating. It seeks, in essence, to be a replacement for C++, the current standard for any low-level game development.</p><p>Many popular languages nowadays, like Python and Javascript, are interpreted<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-4" href="#footnote-4" target="_self">4</a>. This makes them easier to use in many ways than compiled languages like C++, but for tasks like serious game development, where performance is extremely important, the slowness of an interpreted language is unacceptable. In addition to that, many interpreted (and even compiled languages), in pursuit of ease-of-use, tend to obfuscate how your program actually interacts with computer hardware (specifically, for the most part, how your program manages memory). They&#8217;re designed to handle that sort of thing automatically in the background while you deal purely with the abstract logic (i.e. they are &#8216;high-level&#8217;, compared to low-level languages which are closer to the hardware). This does make things easier, but usually results in programs and <em>programmers </em>that don&#8217;t understand what is going on under the hood, which is quite bad for performance.</p><p>C++ is one of the only popular languages that still puts control of the hardware in the hands of the programmer. The language it&#8217;s based on, C, is also like this, but C lacks many of the features of C++ that make it feasible to write very large, complex programs. Even then, the way C++ handles that complexity is, in hindsight, less than ideal, and makes programs unduly hard to maintain and reason about.</p><p>Learning about Jai and the philosophy behind it exposed me to the true gravity of these problems, problems which it is aiming to fix as a C++ replacement. It was also very exciting, the language itself seemed incredibly fun to use compared to the much older and more bloated C++<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-5" href="#footnote-5" target="_self">5</a>, which made the task of serious game engine development under said philosophy seem a lot more manageable. </p><p>Unfortunately, Jai is still unavailable to the general public, which left me experimenting with alternatives. But before I talk about that ordeal&#8230;</p><h2>The innovative, portable elephant in the room</h2><p>As I write this, my Nintendo Switch devkit sits demandingly and NDA-protectedly on the corner of my desk&#8230;</p><p>The biggest, most glaring condition I set for myself as part of developing this engine was that it needed to be able to <strong>run on consoles</strong> (in addition to Windows, Mac, and Linux devices) without much additional work. This meant finding a game development framework that supported the major console platforms. What is a game development framework? <em>You can- </em>totally ask me that question, it&#8217;s not that complicated. Such a framework is basically a collection of existing code (a &#8216;library&#8217;) that you can include as part of your program that handles common tasks such as drawing to the screen, collecting input, playing audio, etc. It also <em>abstracts </em>that functionality across platforms, which means code written using that framework will work across any platform it supports. For example, say I want to draw a rectangle on the screen:</p><ul><li><p>If I was handling this stuff myself, I would have to write different code that draws a rectangle for every single platform I wanted to support, taking into account all sorts of things that differ like how the CPU is built, the graphics interface, requests to the operating system, etc. Obviously, this is extremely time-consuming and complicated and requires an obscene amount of technical knowledge.</p></li><li><p>Alternatively, I can simply tell a framework &#8220;Draw me a rectangle!&#8221;<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-6" href="#footnote-6" target="_self">6</a> and the framework will handle all the complicated stuff for me, changing how it does things under the hood depending on the platform I&#8217;m targeting. Not only does this save me the effort of actually writing the code that draws the damn rectangle, it means I only have to worry about the platform when it really matters. </p></li></ul><p>As you can see, frameworks are an essential tool, and even amongst indie studios which write their own engines it&#8217;s <em>very, very </em>rare to see someone not using one. So, finding the right framework was a must. And while finding one that supported console development was my main goal, I also had a number of other things in mind when looking:</p><ul><li><p>It should be in line with the philosophy outlined in the previous section, i.e. it should be written in a low-level language and able to be used with a low-level language.</p></li><li><p>It should be primarily designed for 2D game development. Often, frameworks created for 3D development (or both 3D <em>and </em>2D development) tend to come with a lot of unnecessary bloat from the perspective of someone like me, who works only in 2D.</p></li><li><p>It should strike a nice balance between having enough features and still being relatively simple and easy to learn.</p></li><li><p>It should be primarily designed for PC and console development, as opposed to mobile development.</p></li><li><p>It should have a track record of quality, commercial indie games being made with it. This is the best proof that a framework is powerful enough to suit the needs of a commercial game developer like me.</p></li></ul><h2>So how did it go?</h2><p>Annoyingly.</p><p>To my surprise and dismay, pretty much the only framework that advertised itself as having full support for all consoles (aside from those used by full-on engines) was <strong><a href="https://monogame.net/">Monogame</a></strong>. At first, this didn&#8217;t seem like the worst thing in the world. It fit most of my criteria and even came with a number of useful tools. And hey, if it was good enough for Terraria and Celeste, surely it would be good enough for me? But Monogame was built on Microsoft&#8217;s old XNA framework, which means it&#8217;s written almost exclusively in and expects you to use <strong>C#</strong>, Microsoft&#8217;s special little language.</p><p>C# is&#8230; in a weird middle ground. It uses Just-In-Time Compilation, which means rather than being compiled ahead of time, a program called a <em>runtime</em>, which is sort of like an interpreter, compiles your program as it&#8217;s running. Sorta. Look, the details aren&#8217;t important; this basically just means that C# is faster than an interpreted language, but more flexible than a compiled language. But, y&#8217;know, you could also rephrase that as it being less flexible than an interpreted language and slower than a compiled language. Especially because C# <em>hates </em>the idea of giving you control of memory&#8230; but I was blissfully unaware of the full extent of this hatred at the time, and so, with a notepad of full of low-level memory tricks I wanted to try out, I decided to jump in and give Monogame a shot.</p><p>Cut to one month later, and I was at my limit. See, C# <em>technically </em>gives you the ability to do low-level memory control, but holy <em>sh&#8212;</em> it&#8217;s like pulling teeth!! Half the language features aren&#8217;t built for it, you have to ask pretty please every time you do it, and whenever I wanted to ask a question about it every forum answer (and half the official documentation&#8230; and ChatGPT&#8230;) basically just told me &#8220;you&#8217;re crazy, don&#8217;t do it&#8221;! They literally call it &#8220;unsafe code&#8221;! And of course, the runtime is so full of implicit background behavior when it comes to this stuff that there&#8217;s <em>never </em>any easy way of knowing if things are working as intended or if you screwed up and wiped out all the performance benefits you were aiming for. The simplest tasks, stretched out into days of infuriating research and fiddling around! What foolery! What nonsense!</p><h2>Uh&#8230; memory&#8230;?</h2><p>Ah. Crap, another computer science lesson. Alright, let&#8217;s get through this quick, I believe in you.</p><p>You might be familiar with the idea that your computer has <em>memory, </em>i.e. places where it stores information (as little numbers) when the CPU isn&#8217;t using it for its little tasks. But did you know that your computer has different <em>kinds </em>of memory? In essence, different memory components on your computer trade-off between how much data they can store, and how quickly the CPU can access them. So a component might be able to store a lot of data, but take a really long time to access; or it might only store a little bit of data, but be really fast to access. Here&#8217;s an overview of the different memory components in a typical PC:</p><ul><li><p>Hard Drive (or &#8216;the disk&#8217;): This is basically &#8220;cold storage&#8221; for your data. Hard drives are <em>huge, </em>with hundreds of Gigabytes or even Terabytes of storage space<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-7" href="#footnote-7" target="_self">7</a>, and they store data even if the computer is powered off, but they&#8217;re <em>really </em>slow to read from. When a game is &#8220;loading&#8221;, it&#8217;s usually because it has to move a bunch of data from the hard drive to RAM. Speaking of&#8230;</p></li><li><p>RAM (Random Access Memory): This is basically where all the programs running on your computer store themselves and any data they&#8217;re currently using, after being loaded in from the hard drive. It&#8217;s called that because you can access any part of it just as quickly as any other part, instead of having to wait for a <em>literal spinning disk </em>to move to the right position. RAM is pretty big, usually capable of storing several gigabytes on modern PCs. It&#8217;s also much faster to read from than a hard drive, but not as fast as&#8230;</p></li><li><p>CPU cache: Your CPU comes with a number of little memory components called &#8216;caches&#8217;, each one smaller and faster than the last. The smallest ones are usually on the order of a few kilobytes. Whenever a program tries to send a piece of data from RAM to the CPU, it (and some surrounding data<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-8" href="#footnote-8" target="_self">8</a>) gets copied to a CPU cache. The <em>next </em>time your program tries to read data from RAM, the CPU will check if it&#8217;s in a cache first. If it is, great! It can just read it from there instead (this is called a &#8216;cache hit&#8217;<em>, </em>and if the CPU can&#8217;t find the data in a cache, it&#8217;s a &#8216;cache miss&#8217;). This is useful because getting data from a cache can be <em>hundreds </em>of times faster than getting it from RAM. </p></li><li><p>CPU registers: This is where the CPU puts data it&#8217;s directly working on. They&#8217;re tiny, usually just a few bytes. If your CPU is in the middle of, for example, adding two numbers together, each of them is gonna take up one register.</p></li></ul><p>So, bringing it back to the earlier discussion, how do different programming languages interact with this stuff? Generally, anything that has to do with memory is considered fairly low-level, so many languages do their best to make it so you don&#8217;t have to think about it. In C#&#8217;s case, it employs a common strategy called &#8216;garbage-collection&#8217;:</p><ul><li><p>Say I want to store a bunch of numbers for later use: in a garbage-collected language, I just need to say &#8220;store those numbers somewhere!&#8221;, that&#8217;s it. Another special program that runs alongside mine, called the &#8216;garbage collector&#8217; (GC), will hand me a reference I can use to get my numbers back later, and I can go about my merry way. The GC will automatically handle putting and shifting those numbers around in RAM, and cleaning them up when my program doesn&#8217;t need them anymore (it does this by continuously checking if the reference it gave me is still in use).</p></li><li><p>In a &#8216;manual memory-management&#8217; language like C, I would be in control of memory, but also responsible for it. So for my bunch of numbers, I&#8217;d have to explicitly ask the operating system for somewhere (in RAM) to put them, make sure there&#8217;s enough space for them, keep track of exactly where they are, move them somewhere else if e.g. I suddenly need to add more numbers than I have space for, and free up the memory as soon as I no longer needed it.</p></li></ul><p>Wow, manual memory management sounds like a pain! Why bother? Well, as mentioned, it all comes down to performance. Running a GC introduces overhead, but worse than that is that in a GC&#8217;d language you have <em>no clue</em> how your program is actually laid out in memory. This makes it basically impossible to optimize your program for the cache, since the main way of doing that is to very carefully arrange your data sequentially in RAM, to minimize cache misses. This is a <em>big deal, </em>even simple programs can, in practice, run <em>dozens to hundreds </em>of times faster if properly optimized for the cache. This makes low-level memory control a must-have if you&#8217;re serious about performance. But as much as C#&#8217;s design insists otherwise, it doesn&#8217;t have to be a nightmare&#8230;</p><h2>Alternatives</h2><p>I can actually remember the specific line of code that shattered my faith in C#<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-9" href="#footnote-9" target="_self">9</a>&#8230; it was time to try something else. After all, in many ways, C# was diametrically opposed to Jai. It&#8217;s a decades-old language designed by committee with a huge emphasis on automatic memory management. Frankly, it&#8217;s a bit crazy that I got as far with it as I did. Perfect, guaranteed console support was just not worth having to use it, so I loosened my criteria: if I could get a test app running on my Switch devkit, that would be good enough for now. With my expectations properly humbled, I decided to look closer to &#8220;home&#8221;.</p><p>It was through my research at this point that I realized that we&#8217;re truly living in a bit of a renaissance period for C-like languages. Jon Blow wasn&#8217;t the only person who saw the need for a new C successor; over the past decade or so, several projects have sprung up trying to be more pleasant alternatives to C/C++ for systems programmers. Go, Rust, Zig, V, and many more have been slowly carving out their own niches. But for my purposes, one language stood out to me: ODIN. </p><p>Created by Bill &#8220;gingerBill&#8221; Hall, <strong><a href="https://odin-lang.org/">ODIN</a></strong> is a C-like language whose design philosophy is squarely in the same camp as Jai&#8217;s, and it shows in both the syntax and language features. It was created primarily to help with the creation of the VFX software that Bill works on, and seems to have been a huge success in that regard<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-10" href="#footnote-10" target="_self">10</a>. It&#8217;s also considered to be incredibly well suited for low-level game development, in-part thanks to its out-of-the-box support for many existing C-based game dev libraries. Most notably: Simple Directmedia Layer 2.</p><p><strong><a href="https://www.libsdl.org/">SDL2</a></strong> is an incredibly popular game development framework with an extremely impressive track record. While I was already aware of it from my previous research and some dabbling years prior, I had glossed over it since it didn&#8217;t seem to advertise having out-of-the-box support for consoles. But color me surprised! Upon closer investigation of an old readme document hosted at the back of their website, I uncovered the existence of official Switch and Xbox ports of the framework!<a class="footnote-anchor" data-component-name="FootnoteAnchorToDOM" id="footnote-anchor-11" href="#footnote-11" target="_self">11</a></p><p>(Now is probably a good time to mention: getting one&#8217;s hands on these sorts of things is a bit of a pain. Console manufacturers are extremely secretive about the inner workings of their machines, so ports like these can&#8217;t be hosted freely alongside the normal framework. They can only be made available to <em>licensed </em>developers, on pain of a visit from the ninjas. Fortunately, I have <em>all </em>the right credentials, so getting access to the Switch port of SDL2 was just a matter of a few twitter DMs.)</p><h2>Hope!</h2><p>The temptation was too strong, I had to try it! I set up Odin on my PC and hooked up my new project with the SDL2 port. This was it! The moment of truth! Would I be able to get a test app written in Odin using SDL2 working on my devkit? </p><p>&#8230;</p><p>Yes, of course, or else we wouldn&#8217;t be here. Did you not read the introduction post? </p><p>Still, it was quite the endeavor. I learned a <em>lot </em>about setting up compilers. After a weekend of desperate trial and error I actually leapt out of my chair and cheered once I got my devkit to display an empty red screen. I can&#8217;t talk too much about it unfortunately, or else the ninjas will be at <em>my </em>door, but let&#8217;s just say that Odin working seamlessly with any existing C code was a big deal.</p><h2>Great success!</h2><p>Indeed. I&#8217;ve been working on the engine for the past couple of weeks now and ODIN has been delightful to use and learn about, a huge improvement over C#. I feel like almost every day I&#8217;m picking up new and better ways of doing things. I didn&#8217;t really touch on Object-Oriented vs Data-Oriented programming in this post, but I might cover it later on; my opinions on the matter are seeing quite the rapid evolution thanks to this language.</p><p>My plan right now is to hit some basic milestones in terms of engine features, build a small prototype game using those features, and make sure everything still works on Switch. An Xbox port of SDL2 exists&#8230; I think&#8230; but that will have to wait until I get access to a devkit. As for Playstation, that console will probably be the hardest to support; it uses a platform-specific graphics API, which in simple terms means that a lot of work specific to that platform has to be put in to get a framework working on it. Likely because of this, SDL2 sadly doesn&#8217;t seem to have a Playstation port. So&#8230; Switch now, Xbox later, and Playstation, uh&#8230; maybe never? We&#8217;ll see.</p><p>Next post, we&#8217;ll finally get into actual engine design, so look forward to it! See you then!</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://blog.massimogauthier.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Subscribe for free to get the next post via email!</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><div><hr></div><p><em><a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non">&lt;&lt;Introduction</a> | <a href="https://massimog.substack.com/p/game-engine-dev-explained-for-non-c31">Next Post&gt;</a></em></p><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-1" href="#footnote-anchor-1" class="footnote-number" contenteditable="false" target="_self">1</a><div class="footnote-content"><p>Oh? Primitive tech youtubers? Did they build their own cameras too, HMM???</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-2" href="#footnote-anchor-2" class="footnote-number" contenteditable="false" target="_self">2</a><div class="footnote-content"><p>Yes, plain text! You could open up notepad right now, write in any language you want, and it would work just fine as a program.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-3" href="#footnote-anchor-3" class="footnote-number" contenteditable="false" target="_self">3</a><div class="footnote-content"><p>Individual instructions really are quite simple. Most of them just boil down to moving a single number from one place to another. It&#8217;s amazing what you can do if you&#8217;re running billions of them per second though.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-4" href="#footnote-anchor-4" class="footnote-number" contenteditable="false" target="_self">4</a><div class="footnote-content"><p>Game Maker Language is a bit of an interesting case. By default, it&#8217;s interpreted, but it can be compiled for a performance boost. As part of its compilation process, it actually gets converted into C++ as an intermediate step! However, the resulting program is still usually quite inefficient compared to one that was written directly in C++.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-5" href="#footnote-anchor-5" class="footnote-number" contenteditable="false" target="_self">5</a><div class="footnote-content"><p>For reference, C++ was released to the public in <em>1985 </em>and <em>to this day </em>still receives a steady stream of revisions and new features. C has been around even longer of course, since 1972, but while it&#8217;s still being maintained it, by design, hasn&#8217;t changed much since then.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-6" href="#footnote-anchor-6" class="footnote-number" contenteditable="false" target="_self">6</a><div class="footnote-content"><p>Well, more like &#8220;<code>SDL_RenderDrawRect(renderer, rect)</code>&#8221;, but you get the idea.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-7" href="#footnote-anchor-7" class="footnote-number" contenteditable="false" target="_self">7</a><div class="footnote-content"><p>As of 2024 lol.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-8" href="#footnote-anchor-8" class="footnote-number" contenteditable="false" target="_self">8</a><div class="footnote-content"><p>As in, whatever data happens to be literally, physically stored next to it in RAM.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-9" href="#footnote-anchor-9" class="footnote-number" contenteditable="false" target="_self">9</a><div class="footnote-content"><p><code>public ref T RefExample&lt;T&gt;(){ return ref new T(); }</code>: Terrible, foolish, ERROR!!</p><p><code>public ref T RefExample&lt;T&gt;(){ return ref (new T[1])[0]; }</code>: Completely fine.</p><p>Clown language.</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-10" href="#footnote-anchor-10" class="footnote-number" contenteditable="false" target="_self">10</a><div class="footnote-content"><p>Said software, EmberGen, is written fully in Odin, and now apparently the industry standard for generating fire and smoke VFX. This is in large part thanks to the fact that, unlike it&#8217;s predecessors, it can render in a matter of minutes what used to take hours or <em>days!!!</em> Wow!</p></div></div><div class="footnote" data-component-name="FootnoteToDOM"><a id="footnote-11" href="#footnote-anchor-11" class="footnote-number" contenteditable="false" target="_self">11</a><div class="footnote-content"><p>Honorable mention: <strong><a href="https://www.raylib.com/">Raylib</a></strong> is a similar framework that was originally envisioned as a friendlier competitor to SDL. Unfortunately, its only switch port is locked away tightly in the avaricious grasp of the publisher who commissioned it, and, based on our conversations, the framework&#8217;s creator does not seem to have the freedom to release it to licensed developers, despite his willingness to do so.</p></div></div>]]></content:encoded></item></channel></rss>