<?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[Entanglement]]></title><description><![CDATA[A studio for leveraging modern computing power for art beyond hyper-realism]]></description><link>https://entanglement.games</link><image><url>https://substackcdn.com/image/fetch/$s_!iud-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F144c49cf-6f1d-495f-b4e9-5f5db0ee3376_403x403.png</url><title>Entanglement</title><link>https://entanglement.games</link></image><generator>Substack</generator><lastBuildDate>Wed, 15 Jul 2026 00:41:44 GMT</lastBuildDate><atom:link href="https://entanglement.games/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Entanglement Software LLC]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[contact@entanglement.games]]></webMaster><itunes:owner><itunes:email><![CDATA[contact@entanglement.games]]></itunes:email><itunes:name><![CDATA[Kathryn Lovell]]></itunes:name></itunes:owner><itunes:author><![CDATA[Kathryn Lovell]]></itunes:author><googleplay:owner><![CDATA[contact@entanglement.games]]></googleplay:owner><googleplay:email><![CDATA[contact@entanglement.games]]></googleplay:email><googleplay:author><![CDATA[Kathryn Lovell]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The Traffic Marshal]]></title><description><![CDATA[Here&#8217;s why the &#8220;realism&#8221; of modern traffic simulations can be so frustrating]]></description><link>https://entanglement.games/p/the-traffic-marshal</link><guid isPermaLink="false">https://entanglement.games/p/the-traffic-marshal</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 14 Jul 2026 13:11:58 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c7059fb6-e940-4442-b307-215b1e51a86e_766x679.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Here&#8217;s why the &#8220;realism&#8221; of modern traffic simulations can be so frustrating: a small traffic jam of individual cars can have a cumulative effect that quickly grows out of hand.</p><p>Traffic engineers model this with the <a href="https://medium.com/@yasingoka/importance-of-volume-delay-function-bpr-parameters-shap-analysis-c86b8bf9364b">BPR equation</a>, which models how real accumulated traffic grows at a quadratic rate relative to capacity.</p><p>If the bottleneck were to suddenly clear, the road downstream can now discharge at full capacity, but cars are still arriving from upstream at some rate. The queue only shrinks at the <em>difference</em> between what can now get through and what&#8217;s still piling in: the drain rate is capacity minus activity, not just capacity.</p><p>So the clearance time depends on how close arrivals still are to capacity. If the road is still busy&#8212;say arrivals are at 90% of capacity&#8212;the queue drains at only 10% of capacity, which means it takes roughly <em>nine times longer to dissipate than it took to form</em> at the same demand. A jam that built over 20 minutes can take a couple of hours to fully unwind if traffic stays heavy.</p><p>This is theoretically realistic&#8212;except, of course, for the part where a road instantaneously increases capacity. That&#8217;s something unique to a computer system overseen by a human player. And that human player craves instant feedback, making the crawling unwind of blocked traffic a real disadvantage in gameplay experience.</p><p>This has informed one of <em>Throughput</em>&#8217;s critical design deviations from other modern citybuilders. Because its representation is pure abstraction&#8212;there&#8217;s no individual car with a physical place along its route&#8212;<em>Throughput</em>&#8217;s system can be highly responsive to changes.</p><p>The pathfinding in <em>Throughput </em>moves as fast as your machine. Critical matching is kicked off near the 4-bar boundary (with predictive heuristics on how long it will take to complete), but the rest is optimized as much as possible in between each tick.</p><p>As it sands now, however, in a city that spans the entire map, we still might see only 20% or so optimize at a time. While still highly dynamic, I wanted more headroom to add depth.</p><p><em>Throughput </em>was built entirely using gdscript, Godot engine&#8217;s special scripting language. All programmers acknowledge scripting languages are notoriously slow, but in a way where we make a sage comment about it and move on, since the benefits in architecture flexibility usually outweigh the costs.</p><p>With algorithmically heavy workloads though, the application starts to run into real performance bottlenecks. In this case, converting to using C++ and creating native architecture builds is one of the strongest tools in the toolbox.</p><p>Making the choice to use C++ means that I&#8217;ll have to compile each build separately on a real machine of each type&#8212;windows, mac, and linux. Not so bad to do once, but incredibly painful to do constantly.</p><p>Therefore, the sharpest approach is the hybrid one&#8212;algorithmic optimization goes into a C++ &#8220;core.&#8221; This allows me to solidify a steady state for what C++ is good at, and I keep flexible gdscript for painting and UI&#8212;what it&#8217;s good at.</p><p>I&#8217;ll show you how to determine when making this structural tradeoff is worth it&#8212;for any language pair.</p><p>When building this sort of cross-language architecture, the boundary between languages is the main thing to worry about. We have to worry about the cost of <em>marshaling</em>: porting data from one language&#8217;s structure to another.</p><p>There&#8217;s one context in which the word &#8220;marshaling&#8221; is very familiar: parsing json into Golang. Converting json into Go data structures is the biggest reason why choosing Go &#8220;because it&#8217;s faster&#8221; is often the wrong path.</p><p>Parsing data into another data structure is typically linear. Therefore, in order to make up for a language swap, you usually look for whether the compute operations scale superlinearly.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!U2kh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!U2kh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 424w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 848w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 1272w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!U2kh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png" width="1456" height="613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:613,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77162,&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://entanglement.games/i/201398232?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.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_!U2kh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 424w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 848w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.png 1272w, https://substackcdn.com/image/fetch/$s_!U2kh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F497a02e9-3a87-4593-8f38-5e9f2e685b62_1944x818.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">marshaling across a language barrier makes sense with superlinear compute cost above a crossover point, or if compute cost always exceeds by some constant</figcaption></figure></div><p>With webservers this often isn&#8217;t the case; the majority of requests are handoff to the database. This is why in performance for frontline servers, Node.js can be the choice that wins: while in Golang you&#8217;d be paying cumbersome cost to marshal json per request, json is quite familiar to Node.</p><p>This method is how we can also examine the tradeoff with gdscript and C++, albeit with slightly different constants: Conversion is more intensive, but the payoff in compute speed is an order of magnitude larger.</p><p>While the theoretical payoff in this case is much more clearly tempting, the case where data is constantly moving across the linguistic boundary a huge potential failure mode. Luckily for this traffic sim, matching and optimization are pretty well isolated&#8212;they&#8217;re already threaded.</p><p>And the payoff is visibly real. On a city that spans the entire map, it can now optimize<em> every link 12x over</em>. To really get a feel for this, you&#8217;ll get to try it yourself: I&#8217;ll soon be releasing a public branch on Steam with the C++ core. You&#8217;ll get to see just how quickly the map changes&#8212;and tell me if it actually feels <em>too </em>responsive.</p><p>There&#8217;s a lot I can potentially do next with all this extra computational space this architecture buys me. That&#8217;s the real beauty in what good performance architecture does: it expands our possibilities.</p>]]></content:encoded></item><item><title><![CDATA[Some Conditions of Macroeconomic Instability]]></title><description><![CDATA[Tynan Sylvester points out in his O&#8217;Reilly book Designing Games that designers must be vigilant for the &#8220;degenerate strategy.&#8221; It's what exploit-hunting YouTubers are hunting for, and unlike a physics glitch, a degenerate strategy sucks the fun out permanently: once known, it can't be unknown.]]></description><link>https://entanglement.games/p/some-conditions-of-macroeconomic</link><guid isPermaLink="false">https://entanglement.games/p/some-conditions-of-macroeconomic</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 07 Jul 2026 13:01:50 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gFtK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Tynan Sylvester points out in his O&#8217;Reilly book <em>Designing Games</em> that designers must be vigilant for the &#8220;degenerate strategy.&#8221; It's what exploit-hunting YouTubers are hunting for, and unlike a physics glitch, a degenerate strategy sucks the fun out permanently.</p><p>The system that undergirds <em>Throughput</em> is a time-tested one: based on the continuous economic system first introduced by <em>SimCity</em>. Residential population creates demand for Commercial, which in order to have goods to supply, creates demand for Industrial. This core gameplay loop works so well that it became the foundation of a whole genre.</p><p>When I first developed the system that undergirds <em>Throughput</em>, I created similar requirements for these zones in a 1:1:1 ratio: one resident requires one good, one good requires one unit of freight, and one unit of freight requires one worker.</p><p>You can imagine this quickly devolved into a degenerate strategy: small atomic clusters of zones could be placed in a repeated alternating tile pattern for perfect satisfaction&#8212;not very interesting.</p><p><span>I had to go back and look at what the ratio looked like in </span><em>SimCity 4</em><span>. Simple enough to observe&#8212;at least at low densities&#8212;the demand for Residential zones far outpaced the demand for Industrial.</span></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TpD4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TpD4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TpD4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg&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;:753430,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://entanglement.games/i/203963229?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TpD4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 424w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 848w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!TpD4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb6a9d38e-0ebb-4825-94c0-4c6e139974d4_1920x1080.jpeg 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>So I decided to tweak the ratios. Once again emphasizing the power of a <a href="https://klovell.substack.com/p/game-designers-love-xml">tunable system</a> for defining zone supply and demand, I arrived at these levels:</p><ul><li><p>ADULT (Residential): produces 1 ADULT, needs 1 GOOD &#8594; column ADULT: 1 GOOD.</p></li><li><p>GOOD (Commercial): produces 3 GOOD, needs 1 ADULT + 1 FREIGHT &#8594; per unit GOOD: &#8531; ADULT, &#8531; FREIGHT. (the &#8531;s come from dividing by the batch size of 3.)</p></li><li><p>FREIGHT (Industrial): produces 1 FREIGHT, needs 3 ADULT &#8594; column FREIGHT: 3 ADULT.</p></li></ul><p>The most important aspect being 1 freight requiring 3 adults.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gFtK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gFtK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 424w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 848w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gFtK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png" width="1456" height="819" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png&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;:2799479,&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://entanglement.games/i/203963229?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.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_!gFtK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 424w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 848w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.png 1272w, https://substackcdn.com/image/fetch/$s_!gFtK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6fcdde5c-0d21-4580-af0f-c30d9c0aba9f_3840x2160.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>Empirically, this works. The system demands it grow constantly to be viable, and I&#8217;ve watched multiple smart people attempt to develop a degenerate strategy for it to no avail. But can we <em>prove</em> that it works?</p><p>One nice thing about human-designed systems: they can be exact fits to what humans conceived of for real-world abstraction&#8212;the map <em>is</em> the territory.</p><p>And there&#8217;s one particular abstraction from macroeconomics that fits perfectly here: a Leontief-style input-output model.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j5BX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j5BX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 424w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 848w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 1272w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j5BX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png" width="1456" height="583" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:583,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:305042,&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://entanglement.games/i/203963229?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.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_!j5BX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 424w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 848w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.png 1272w, https://substackcdn.com/image/fetch/$s_!j5BX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6747600f-1780-47c8-89fd-532557edd3fe_1668x668.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 <a href="https://en.wikipedia.org/wiki/Hawkins%E2%80%93Simon_condition">Hawkins-Simon condition</a> comes from a 1949 <em>Econometrica</em> paper titled "Some Conditions of Macroeconomic Stability." It &#8220;<span>guarantees the existence of a non-negative output vector that solves the </span>equilibrium<span> relation in the </span>input&#8211;output model<span> where </span>demand equals supply<span>.&#8221;</span></p><p><span>In other words, Hawkins-Simon checks whether a system is &#8220;productive:&#8221; that every part of the output vector is greater than 0 means that there is only positive output from the system, and nothing is at a deficit.</span></p><p><span>On the flip side, this means that if any of the parts is less than zero, then the system runs at a deficit. The boundary where the determinant equals zero&#8212;the 1:1:1 ratio I mentioned before&#8212;describes a </span><em><span>degenerate matrix</span></em><span>.</span></p><p>Geometrically a determinant is the volume-scaling factor of a linear map. I &#8722; A maps gross output &#8594; net-output-available. So <em>det</em>(I &#8722; A) measures how much net surplus the <em>entire web</em> output per unit of gross activity, as one number.</p><p>By looking at the leading principal minors&#8212;the determinant of each submatrix&#8212;we can determine exactly where this system begins to tip negative. </p><p>Leading principal minors of I &#8722; A:</p><ul><li><p>1st (Adult alone): <strong>1</strong> &#10003;</p></li><li><p>2nd (Adult + Good): 1 &#8722; 1/3 = <strong>2/3</strong> &#10003;</p></li><li><p>3rd (full system): expanding, det(I &#8722; A) = 1 &#8722; 1/3 &#8722; 1 = <strong>&#8722;1/3</strong> &#10007;</p></li></ul><p>The Hawkins-Simon condition is failed at the third minor. The residential/commercial pair would be a viable economy on its own <em>if freight were free</em>. The 3-workers-per-freight cost is where the deficit enters the web.</p><p>What we&#8217;ve found in the principal minors can be further described by the spectral radius: the characteristic polynomial is &#955;&#179; &#8722; &#955;/3 &#8722; 1 = 0, whose real root is<strong> 1.11</strong>.</p><p>What the spectral radius tells us is ultimately simple to express: each unit of final consumption demands ~1.11 units of upstream production, compounding ~11% per propagation round. The system fails viability, but <em>barely</em>. Decay is the default, but it&#8217;s a slow leak, not a rupture.</p><p>The only source of viability in this system is the one thing outside the matrix: the player. Every action is an injection the economy can't generate alone. Mierle Laderman Ukeles called this <a href="https://bsky.app/profile/throughputgame.bsky.social/post/3mna5abheex2r">maintenance art</a>; the work of keeping the system alive is in itself the work.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ni3L!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ni3L!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 424w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 848w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 1272w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ni3L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp" width="1054" height="744" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:744,&quot;width&quot;:1054,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!Ni3L!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 424w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 848w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 1272w, https://substackcdn.com/image/fetch/$s_!Ni3L!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcf2d2b97-13d7-446b-9094-0f957f904ed3_1054x744.webp 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>There&#8217;s a certain point at which systems thinking must feed back into systems <em>feeling</em>.</p><p>As I was tuning my Degenerate state's pruning of unmatched cells, I looked to sharpen the cut between it and Euphoric, which is a Throughput-induced spurt of unchecked growth. Euphoric and Degeneration name the two open half-spaces, and the uninhabitable degenerate <em>point</em> sits unnamed between them as the threshold you're always crossing. </p><p>Degeneration can be difficult to keep up with. When Euphoric mode is reached (and finally disables pruning) I&#8217;m like, "phew, I can take a breath for all of two seconds." </p><p>Euphoric isn't a reward state, but a release state. Typically only the former is emphasized in game design. But reward states are flat dopamine; you did the thing, here's the cookie.</p><p>Release states require <em>prior tension</em>. They're earned by surviving pressure. The difference matters because reward states get less satisfying with repetition (tolerance builds, the cookie gets smaller), while release states stay satisfying as long as the tension is real (because each tension is its own arc).</p><p>Spectral radius = 1.00 is subsistence, spectral radius = 1.67 would be <a href="https://youtu.be/6TK377Cyoj0">freefall</a>, spectral radius = 1.11 is a game.</p><p>Soon you&#8217;ll be able to feel this for yourself, <a href="https://store.steampowered.com/app/4535370/Throughput/">as the demo launch is imminent</a>. Build your city. Watch it breathe.</p>]]></content:encoded></item><item><title><![CDATA[What do you call a 141x Algorithmic Improvement?]]></title><description><![CDATA[There&#8217;s an ancient computing proverb that goes something like this: &#8220;If you improve something 1.2x, you probably just did something smart.]]></description><link>https://entanglement.games/p/what-do-you-call-a-141x-algorithmic</link><guid isPermaLink="false">https://entanglement.games/p/what-do-you-call-a-141x-algorithmic</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Wed, 03 Jun 2026 13:01:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!RmXy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There&#8217;s an ancient computing proverb that goes something like this: &#8220;If you improve something 1.2x, you probably just did something smart. If you improve something 10x, you probably just stopped doing something stupid.&#8221; One might wonder how this extrapolates to a 141x improvement. In this case, it&#8217;s something like &#8220;you probably planned to be stupid.&#8221;</p><p><a href="https://www.throughput.gg/">Throughput</a> is a city builder game: simulated people have homes, they go to work, they buy things. I wanted to make the simulation as dynamic as possible&#8212;if someone found a job with a shorter commute, I want them to take 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_!RmXy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RmXy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 424w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 848w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 1272w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RmXy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png" width="1456" height="814" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.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;:4312317,&quot;alt&quot;:&quot;&quot;,&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://klovell.substack.com/i/199774425?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!RmXy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 424w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 848w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.png 1272w, https://substackcdn.com/image/fetch/$s_!RmXy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F926e2958-87d0-4b36-a2f7-9826b360ebe8_2940x1644.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">live your best on-site life!</figcaption></figure></div><p>This means it&#8217;s a gigantic pathfinding network flow problem&#8212;and it was beginning to have some problems. On &#8220;large&#8221; games, I was already starting to see visible simulation slowdown.</p><p>The visibility and interaction slowdown I mitigated via threading and by holding copies of the simulation while the thread completes. Still, Throughput is a game in time with music, and I intend for simulation refreshes to be snappy&#8212;it&#8217;s an intuitive feel problem if it isn&#8217;t. And I knew I wanted my games to get 10x larger.</p><p>The work I did threading the simulation built a solid foundation of feature-specific tests via automating <a href="https://klovell.substack.com/p/agentic-coding-enables-real-software">Test Driven Development</a>. Crucially, I also created save games that I then use as benchmarked test fixtures. These guardrails are the &#8220;plan to be stupid&#8221; I made right before I blindly tell Claude to optimize against the benchmark.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rTJ0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rTJ0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 424w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 848w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 1272w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rTJ0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png" width="862" height="174" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:174,&quot;width&quot;:862,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:39457,&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://klovell.substack.com/i/199774425?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.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_!rTJ0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 424w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 848w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 1272w, https://substackcdn.com/image/fetch/$s_!rTJ0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ada45e8-f223-4925-8d34-41d78e087f68_862x174.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">your Core Web Vitals could never</figcaption></figure></div><p>The core of our simulation uses <a href="https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm">Dijkstra&#8217;s pathfinding algorithm</a>. Most of our calls are multi-target, so we don&#8217;t go for A*. Ironically, this is where the first 36x optimization came from: removing early-termination that would make sense for the single-target case.</p><p>Dijkstra from a single source is already naturally a multi-target algorithm. If you let it run, the first time it pops node X is the moment it knows the cost-min distance from source to X. That's true for every node, simultaneously, from one expansion.</p><p>The rest of it? Depth pruning: We don&#8217;t need to expand paths that are already worse than the current one.<br><br>But the actual how is just the artifact of how I found it. Everything is ultimately a search problem: if there&#8217;s something you want to achieve, there exists a path to get you there. Search is the act of finding it&#8212;so execution of your strategy rests on your search tactics.<br><br>In this case we employ a particular tactic for working with black box systems: you look at your inputs and outputs. I knew my inputs (test fixture), and I had the expected outputs (unit tests, benchmarking).</p><p>It&#8217;s often repeated that you should &#8220;be specific&#8221; when talking to computers, but it&#8217;s important to examine what that actually means. A figure takes shape only via its negative space&#8212;being specific is as much about what you don&#8217;t require as much as it is about what you do. That flexibility is what makes room for what you care about.</p><p>It&#8217;s fine that the first implementation wasn&#8217;t optimal&#8212;it did what it needed to until it didn&#8217;t. That&#8217;s what iteration is for. In fact, at its core <em>O(VlogV)</em> Dijkstra still shows pretty uncontained growth; now that the truly na&#239;ve implementations are fixed, we&#8217;re going to have more specific tradeoffs to make.</p>]]></content:encoded></item><item><title><![CDATA[It's too bad Valve isn't publicly traded, because they might eat Microsoft's lunch]]></title><description><![CDATA[The Year of the Linux Desktop]]></description><link>https://entanglement.games/p/its-too-bad-valve-isnt-publicly-traded</link><guid isPermaLink="false">https://entanglement.games/p/its-too-bad-valve-isnt-publicly-traded</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Wed, 20 May 2026 13:01:41 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!j3Tu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>About a year ago, I started to really feel the pain in that a 500 GB SSD was apparently no longer large enough for a gaming PC. So I replaced my old drive with a 4 TB 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_!j3Tu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j3Tu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 424w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 848w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j3Tu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg" width="1456" height="987" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:987,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Image&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="Image" title="Image" srcset="https://substackcdn.com/image/fetch/$s_!j3Tu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 424w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 848w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!j3Tu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b4d819d-47df-4a9b-a914-27833f06296b_2048x1388.jpeg 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">The NVMe form factor still shocks me</figcaption></figure></div><p>I did not want to deal with copying my drive over with <a href="https://www.geeksforgeeks.org/linux-unix/dd-command-linux/">dd</a> (a.k.a. the data destroyer) or any of the random third-party software with which you&#8217;re expected to port Windows to a new drive. Or with Windows license keys. Or with Windows.</p><p>Lately, I&#8217;m not the only one. The negative sentiment against Windows (and other Microsoft software) has reached a cultural breaking point: the most memorable quote from the Artemis II flight (to the moon!) was &#8220;<a href="https://www.reddit.com/r/pcmasterrace/comments/1sao0kh/artemis_ii_astronaut_reports_to_nasa_that_two/">I have two versions of outlook and neither are working.</a>&#8221;</p><p>But simply annoying your users isn&#8217;t enough. Companies often conclude that their user annoyance is worth the tradeoff, because they don&#8217;t immediately see any real effects on user engagement or churn. This works so long as the company&#8217;s moat remains intact: without the presence of a viable alternative, you can pretty much perpetually mask dissatisfaction&#8212;that is, until the dam breaks.</p><p>Enter SteamOS. It&#8217;s entirely possible&#8212;thanks to the efforts of Valve (the creators of Steam, and more importantly, the version of Linux they created for their Steam Deck)&#8212;that Microsoft may lose its positioning.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dtpA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dtpA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 424w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 848w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dtpA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png" width="1456" height="805" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:805,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1063049,&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://klovell.substack.com/i/198282286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.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_!dtpA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 424w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 848w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!dtpA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4850e743-ed97-4edd-a3db-b7d9f70918a9_2376x1314.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">And now, the Steam Machine&#8212;Steve Jobs would&#8217;ve been jealous they managed to make the Perfect Cube</figcaption></figure></div><p>They&#8217;re a big reason why many of my favorite games have native Linux builds, that many say <a href="https://www.reddit.com/r/RimWorld/comments/1rl92ip/comment/o8qe7k6/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">run better than on Windows</a>. But even more wildly, Steam&#8217;s version of WINE compatibility layer, <a href="https://www.protondb.com/">Proton</a>, actually works. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TaCZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TaCZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 424w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 848w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 1272w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TaCZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png" width="1456" height="654" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:654,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:536811,&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://klovell.substack.com/i/198282286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.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_!TaCZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 424w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 848w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.png 1272w, https://substackcdn.com/image/fetch/$s_!TaCZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0caaa03f-dc7a-48b3-be75-6dd95b7ac512_1762x792.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">There was a certain era of programming taxonomy that loved self-referential acronyms, i.e. YAML Ain&#8217;t a Markup Language. In this era, WINE being useful was mythological</figcaption></figure></div><p>My gaming machine began its new life as a Linux Mint machine thanks to Proton. This allows me to run even Windows builds, even for graphically intensive games like Cyberpunk 2077&#8212;the type most historically dependent on Windows scaffolding. There goes Microsoft&#8217;s moat.</p><p>At least a big chunk of it. This win will need to generalize to more diverse types of software. This is a lot more viable than it might initially seem&#8212;in fact, it&#8217;s the biggest success story of the decade: the chips NVIDIA developed for gaming ended up as the backbone of AI.</p><p>I had originally played Cyberpunk 2077 on the Switch 2&#8212;the main reason I brought Cyberpunk 2077 to Steam was to try to mod it. But it wasn&#8217;t just the game itself I needed to run&#8212;I would also need it mod utility WolvenKit, a non-Steam Windows program. It was WolvenKit that clued me into my most recent experiment.</p><p>You see, there was one more Windows program I found myself rebooting for (on the occasion I&#8217;m not simply being a degenerate gamer): <a href="https://www.ableton.com/en/">Ableton Live</a>&#8212;a digital audio workstation meant for music production.</p><p>I decided to try running Ableton the same way I ran WolvenKit&#8212;quote via <a href="https://wiki.redmodding.org/wolvenkit/getting-started/download">the Linux instructions</a>: </p><p><code>Now here's where it gets weird, open Steam and go to your library. Find the "Games" tab on the menu bar, and click on "Add a Non-Steam Game to My Library"</code></p><p>I apply this technique to the Ableton executable, and voila! I can run it using the Proton compatibility layer.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7SAK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7SAK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 424w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 848w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 1272w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7SAK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png" width="1456" height="699" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:699,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:508995,&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://klovell.substack.com/i/198282286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.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_!7SAK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 424w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 848w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.png 1272w, https://substackcdn.com/image/fetch/$s_!7SAK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf64c344-3b6d-4a69-ab5b-56968a2095fd_2626x1260.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 said, getting <a href="https://en.wikipedia.org/wiki/Audio_Stream_Input/Output">low-latency audio drivers</a> to work will be a different story&#8212;it&#8217;s still not as good as a Mac&#8217;s Core Audio, which astoundingly is low-latency out of the box. Linux has more annoying solutions for this, and so does Windows&#8212;and it&#8217;ll be a combination of getting both to work to get them within the compatibility layer.</p><p>Apple wins by a landslide in this regard because they were building Garage Band and Pro Tools, and wanted to make them great. (Now, if only it could work on custom hardware&#8230;)<br><br>The Proton development story is practically a page right out of Apple&#8217;s playbook. They have a specific use case in mind that they intend to make flawless through every part of the stack&#8212;including vertical integration via hardware.</p><p>What&#8217;s often ignored is how well this strategy ends up generalizing. Great support for Pro Tools means great support for Ableton. Great support for SteamOS means great support for Linux. A great whole is the sum of great parts.</p><p>Valve is experimenting with a sweet spot, blending what worked about the Apple strategy with filling the decentralized customization gaps previously patched by Windows. Look at it from a slightly different angle, and you find they&#8217;re actually doubling down&#8212;on the &#8220;great parts&#8221; method.</p><p>That&#8217;s a remarkable way to dig away at Microsoft&#8217;s moat&#8212;until suddenly, the moat&#8217;s drained entirely.</p>]]></content:encoded></item><item><title><![CDATA[Finding the Musical Cutting Edge, Topologically]]></title><description><![CDATA[We&#8217;re going to have to talk about genre.]]></description><link>https://entanglement.games/p/finding-the-musical-cutting-edge</link><guid isPermaLink="false">https://entanglement.games/p/finding-the-musical-cutting-edge</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Wed, 29 Apr 2026 13:27:40 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!4L3i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>We&#8217;re going to have to talk about <em>genre</em>.</p><p>And genre is an intimidating topic to talk about. On the one hand it can bring out the most rigid and persnickety in us, such that on the other hand it almost seems necessary to throw up our hands and deem it reductive. But failure to describe begets failure to have the thought entirely, so is not outright anti-intellectual to reject categorization&#8212;reject <em>naming</em> things?</p><p>Unfortunately for you all I&#8217;m an Engineer, so I reduce intellectualism to practicality. And there&#8217;s two primary benefits I see to pushing forward on conversations about genre:</p><ul><li><p>Discerning what makes a piece work. As an artist, it&#8217;s useful to deconstruct and seek commonalities. It&#8217;s the equivalent of taking apart an electronic device to see how it works and putting it back together again.</p></li><li><p>Distinguishing relevance and legibility: there&#8217;s such a thing as a piece that is <em>too</em> original. While an artist may have esoteric ideas, a piece of work that is too far removed from existing work is doomed never to be understood&#8212;even by the artist, the art forever stuck as a vague idea.</p></li></ul><p>As an exploratory example, let&#8217;s examine the path to possibly one of the most acoustically gobsmacking moment in music history: the journey of the artist Sonny Moore, a.k.a. Skrillex. His debut EP <a href="https://www.youtube.com/watch?v=WSeNSzJ2-Jw&amp;list=RDWSeNSzJ2-Jw&amp;start_radio=1">Scary Monsters and Nice Sprites</a> (as the name suggests, a love letter to the call-and-response composition method) was explosive material back in 2010. It was a total maximalist subversion of Dubstep, a surprisingly <a href="https://www.youtube.com/watch?v=8k_f2QK77ew&amp;list=RDOs9DYRZyk-w&amp;index=3">minimal</a> genre at its core. So much so, that &#8220;UK Dubstep&#8221; and &#8220;American Dubstep&#8221; (or &#8220;<a href="https://youtu.be/-hLlVVKRwk0?si=TsOnU3HoX892znC0&amp;t=1160">Brostep</a>&#8221;) are now often considered separate genres.</p><p>But Moore&#8217;s musical journey didn&#8217;t begin with the Skrillex project. He had previously done vocals for a &#8220;Screamo&#8221; band called <a href="https://www.youtube.com/watch?v=tJokI__-A8w&amp;list=RDtJokI__-A8w&amp;start_radio=1">From First to Last</a>, which combines influences from the Emo and Metal genres. He learned sound design with the influence of <a href="https://www.youtube.com/watch?v=fZAhJkswLEE&amp;list=RDfZAhJkswLEE&amp;start_radio=1">Noisia</a>, who primarily worked within the Drum and Bass genre (arguably Brostep&#8217;s closest relative).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4L3i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4L3i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 424w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 848w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4L3i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png" width="1456" height="1126" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1126,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:170085,&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://klovell.substack.com/i/191922480?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.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_!4L3i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 424w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 848w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.png 1272w, https://substackcdn.com/image/fetch/$s_!4L3i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbc309a79-1455-4530-b332-b0c9d30e1318_1780x1376.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">obligatory caveat that it goes deeper than this (to the point where it probably doesn&#8217;t have a planar embedding)</figcaption></figure></div><p>It&#8217;s worth noting the crescendo of Skrillex&#8217;s artistic arc didn&#8217;t culminate until a year later, when he reached for even more estranged rock influences to create what in my opinion will go down as one of the greatest works of the 21st century: <a href="https://www.youtube.com/watch?v=nUA8OzQxGxE&amp;list=RDnUA8OzQxGxE&amp;start_radio=1">Breakin&#8217; a Sweat</a>, the track he created <a href="https://youtu.be/pT40_00AGQU?si=xtJBBc7tLcdkJrRm">with The Doors</a>, topped off with an ancient clip of Jim Morrison himself <a href="https://youtu.be/iS3dIyHpAgc?si=0htaUmqO4fGjVf_Y">predicting Skrillex&#8217;s existence</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6rNU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6rNU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 424w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 848w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 1272w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6rNU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png" width="1382" height="220" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:220,&quot;width&quot;:1382,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:65232,&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://klovell.substack.com/i/191922480?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.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_!6rNU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 424w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 848w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 1272w, https://substackcdn.com/image/fetch/$s_!6rNU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6add29a-1a72-448c-b294-8852a63ab48b_1382x220.png 1456w" sizes="100vw"></picture><div></div></div></a><figcaption class="image-caption">on Jim Morrison&#8217;s predictions</figcaption></figure></div><p>There&#8217;s a lot of information apparent in this graph alone, and it roughly mirrors the way Jim Morrison is thinking about it&#8212;as a progressive branch and merge, an evolution.</p><p>American Dubstep was a massive distillation of many genres that came before it. One might expect that to mark the beginnings of a Cambrian explosion&#8212;instead, it was more like an extinction event. Its legacy mostly consists of works that, while often good, are nonetheless <a href="https://www.youtube.com/watch?v=6JYIGclVQdw&amp;list=RD6JYIGclVQdw&amp;start_radio=1">self-referential</a>.</p><p>The best-fitting model to describe what&#8217;s happened here is a Thomas Kuhn <a href="https://en.wikipedia.org/wiki/Paradigm_shift">paradigm shift</a>: wherein a revolutionary idea is born from pushing up against the boundaries of the current ways of thinking&#8212;once the revolution happens, we begin again to explore the current New Idea to its fullest potential. I think this ultimately is a good signal for American-style Dubstep: that it feels fully-explored doesn&#8217;t mean it&#8217;s done with, it means it&#8217;s ready for another subversion.</p><p>The conclusion itself is perhaps less fascinating than the structures that let us derive it. Structurally, genre information is typically stored as a tag system. A given song is tagged with, e.g. Electronica. There&#8217;s circumstances where tag systems are really powerful&#8212;it&#8217;s often the better way to structure a filesystem when everything is indexable on a pivot. But there&#8217;s another way to organize files that has proven incredibly effective for tracking complex, continuously updating work, and that&#8217;s <a href="https://en.wikipedia.org/wiki/Git">git</a>&#8212;structured as a Directed Acyclic Graph like the one above.</p><p>What about the second use case, distinguishing relevance? Tag systems can do pretty well at recommendation, especially when extended to multi-tag or subcategorical systems. But from the venn diagram illustration below, we can see we easily lose a lot of relevant information to the conversation we just had above.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wXFR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wXFR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 424w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 848w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 1272w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wXFR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png" width="1456" height="841" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:841,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:126442,&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://klovell.substack.com/i/191922480?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.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_!wXFR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 424w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 848w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.png 1272w, https://substackcdn.com/image/fetch/$s_!wXFR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc2bd0d55-02b7-467a-8390-d1d95449adff_1658x958.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>You&#8217;ll notice that, while we can put a good chunk of Skrillex&#8217;s influences under the &#8220;Electronic&#8221; category, we lose all association with his previous Rock-adjacent roots. An American Dubstep enjoyer might very easily get more out of the Metal category than they would out of UK Garage&#8212;or anything House-adjacent. In fact, although not officially categorized yet, I think that&#8217;s the new paradigm the music of the 2020s is <a href="https://www.youtube.com/watch?v=KrtURNplh6w&amp;list=RDKrtURNplh6w&amp;start_radio=1">ramping up to explore</a>.</p><p>Category graphs an be as granular as necessary&#8212;so granular, in fact, that the categorization can be at the level of an individual work. We can define not by the node but its edges&#8212;making the categorization so implicit that it practically melts away completely. This is fundamentally different from an outright refusal to categorize: with this&#8212;yet another model that ends up subverting what it intended to grasp&#8212;we end up with decidedly useful lines of pursuit to aid in understanding our own creation.</p>]]></content:encoded></item><item><title><![CDATA[Agentic Coding Enables Real Software Engineering]]></title><description><![CDATA[The most interesting problem in software is communicating precisely and efficiently]]></description><link>https://entanglement.games/p/agentic-coding-enables-real-software</link><guid isPermaLink="false">https://entanglement.games/p/agentic-coding-enables-real-software</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 21 Apr 2026 14:08:02 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3185e7d1-6214-4a55-b5b5-be5a188c0d2d_1080x719.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Once the game I&#8217;m working on for the Cursor vibe jam, <a href="https://uuqv.itch.io/galactic-golf">Galactic Golf</a>, got past Level 6 or so, I began to have two concerns:</p><ul><li><p>The code built with too many individual features would need a refactor</p></li><li><p>Refactoring would introduce more regressions than I could easily test at once</p></li></ul><p>I&#8217;d first experienced the former situation building <a href="https://uuqv.itch.io/simple-city">Supply and Demand</a>; certain features that had a lot of commonality were getting more and more one-off data structures and references, and many features were getting dumped into a single file, and it was becoming a lot of context for Claude to read. I wanted to refactor these into <a href="https://klovell.substack.com/p/game-designers-love-xml">an extensible framework</a>, so that I could add features without needing to edit the code at all.</p><p>When it came to Galactic Golf, I made sure to add a modular structure for scenes governing levels early on. However, physics simulation is something I definitely have less personal knowledge of, and therefore something I have to abdicate some control over. As the complexity grew, I wanted a way to iterate more quickly while automating correctness guarantees.</p><p><a href="https://en.wikipedia.org/wiki/Test-driven_development">Test-driven development</a> is not a new idea in software, and it&#8217;s one of the best ones&#8212;sort of a platonic ideal. It works incredibly for most logistical correctness guarantees. However, it seems hardly practical for most application development, particularly when using modern frontend and UI frameworks, which often depend heavily on the  all-encompassing state and context of the app to execute anything.</p><p>AI can change this dramatically. The Bot is good at handling the particular idiosyncrasies that come with writing tests for specific frameworks&#8212;what state needs to be mocked around testing the actual logic that needs testing.</p><p>We also tend to feed bite-sized features to AI, which in a way is the pinnacle of what frameworks like <a href="https://github.com/cucumber/cucumber-ruby">cucumber</a> attempt to achieve: articulating your test cases as plain English, so that they serve practically as a common specification.</p><p>So, for Galactic Golf, I devised an experiment to test this method. After generating an initial suite of tests for the features already implemented, my instructions for Claude would be: for every new use case, to write a test first. It would run the test, make sure it failed in an expected way, and then run the test again after implementing the feature&#8212;typical test-driven development.</p><p>My claude.md looks something like this:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;markdown&quot;,&quot;nodeId&quot;:&quot;37c15378-c862-4177-a8ed-0f94cc3de73d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-markdown">## Testing Requirements

Every new feature must have tests. Follow TDD:

1. **Write tests first** in `tests/` before implementing the feature.
2. **Run tests before implementation** to confirm they fail:
   ```sh
   godot --headless --path . -s addons/gut/gut_cmdln.gd
   ```
3. **Implement the feature.**
4. **Run tests again** to confirm they pass.
</code></pre></div><p>Now I put it to the test with an extensive refactor. It&#8217;s good for refactors to have a clear product case: A couple of times, I had to make sure changes to ball physics also applied to the projected trajectory.</p><p>With the TDD framework, I asked Claude to refactor the code such that both ball and trajectory share physics, so we wouldn't need to make changes in two places.</p><p>Did the tests make this a flawless process? Not entirely. At first it didn&#8217;t understand that sharing the physics would mean more than just having a set of separate shared physics functions in the same file, it would mean that both code paths need to call on the same aggregate function.<br><br>When you tell Claude to go against its embedded behavior, it tends to revert to its old behavior in new context windows. So it&#8217;s worth noting I also told Claude to add a comment for itself so that it&#8217;ll remember to use the new function:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nYey!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nYey!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 424w, https://substackcdn.com/image/fetch/$s_!nYey!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 848w, https://substackcdn.com/image/fetch/$s_!nYey!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 1272w, https://substackcdn.com/image/fetch/$s_!nYey!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nYey!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png" width="1244" height="732" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:732,&quot;width&quot;:1244,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105012,&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://klovell.substack.com/i/194335704?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.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_!nYey!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 424w, https://substackcdn.com/image/fetch/$s_!nYey!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 848w, https://substackcdn.com/image/fetch/$s_!nYey!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.png 1272w, https://substackcdn.com/image/fetch/$s_!nYey!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8f0c7373-765b-49fc-98e9-61fb5e6ae06c_1244x732.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 thinks this is for me</figcaption></figure></div><p>Did all of this help? Ultimately I&#8217;m not entirely sure. It&#8217;s always difficult to tell what incidents you&#8217;ve prevented. I&#8217;ve definitely still had to find many issues through manual testing, and then the other half of the time tests seem to be false positives&#8212;and just require a fix to the test itself.</p><p>I think it&#8217;s gotten better the more the codebase has evolved into tests driven by the actual use cases&#8212;beyond what was set up initially. Still, unit tests never tested whether something officially &#8220;works,&#8221; they just test that &#8220;it&#8217;s not broken in one particular way.&#8221; That&#8217;s maybe initially disappointing, but there&#8217;s real cumulative value in that.</p><p>It&#8217;s worth noting that this method consumes significantly more tokens. Luckily, I&#8217;ve configured Claude globally to use the <a href="https://github.com/JuliusBrussee/caveman">caveman skill</a>, which eliminates unnecessary LLM yapping (though it seems to have no effect on thinking). This allows me to even use Claude Opus (which I find is much better at refactors) by default on my $20 plan, only rarely running into my rate limit. I often find the default output way too wordy anyway; it becomes exhausting to parse during long sessions&#8212;ultimately not an efficient use of human brainpower either.</p><p>One thing&#8217;s for certain: even in the age of LLMs, there&#8217;s still great depth to be found in the field of Software Engineering. Many of the most interesting problems have always been&#8212;and remain&#8212;around how best to communicate complex problems and features precisely and efficiently.</p><p>From this perspective, it&#8217;s easy to see how agentic coding will only increase the need for Software Engineering as a field. It&#8217;s also easy to see how they&#8217;ll be an incredible point of advancement for the field itself, in giving us the greater means to leverage our principles.</p>]]></content:encoded></item><item><title><![CDATA[Ads, Subscriptions, and the Internet Without Either]]></title><description><![CDATA[The internet has a glaring monetization gap.]]></description><link>https://entanglement.games/p/ads-subscriptions-and-the-internet</link><guid isPermaLink="false">https://entanglement.games/p/ads-subscriptions-and-the-internet</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 13 Apr 2026 13:32:14 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9d21c982-67ea-41fc-bd21-47aedd9adc84_550x323.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The Common Display Ad Slot on <a href="https://www.youtube.com/watch?v=pTG_6ypYSS4">Al Gore&#8217;s internet</a> will auction off for <strong>$</strong>0.50 by the thousand. As in, you&#8217;ll have to show a thousand ads just to earn 50 cents. If you&#8217;re lucky, a Daily Active User for your site might see that ad 30 times, yielding you a whopping $0.015: one and a half cents.</p><p>By contrast, the lowest priced consumer subscription is typically $2.99 a month. Even at the lower end, that&#8217;s a vast difference from $0.015 a month. When such a large gap exists, it&#8217;s hard not to <a href="https://youtu.be/xbiDrzTd8fE?si=TNkeF455sS00iIAv&amp;t=51">smell an opportunity</a>.</p><p>Given this gap in price, you&#8217;re well motivated to do everything in your power to convert that Daily Active User into a paid subscriber. But doing that will&#8230;take quite some doing.</p><p>To begin with, most consumers do not want <em>yet another</em> subscription. On top of that, there&#8217;s payment processors, who charge a <a href="https://x.com/mattwelter/status/2040492321595343207">7% fee</a> on every one of these transactions. Paradoxically, these sources of friction make it hard to justify pushing your subscription price any lower.</p><p>And just what differentiates your paid service from your free one anyway? Typically, the subscription model resorts primarily to adding more and more ads until the user is over-encumbered by them&#8212;which I suppose is one way to marginally close the revenue/usage gap. It&#8217;s also playing a dangerous game with nuking your user engagement entirely.</p><p>I was <a href="https://youtu.be/n_8YawtKSSk?si=eilXZTkKfyWyCsbS">asked recently</a> if we all could simply do without ads. Wildly enough, in the opportunity to make more money, exists the opportunity for a better internet, better products, and a better internet.</p><p>To do that we&#8217;re going to take some good ideas from the past. Newspapers floundered under subscription models, but they thrived when you could buy one at the newsstand for 5 cents.</p><p>I&#8217;ve implemented a version of this <a href="https://uuqsims.com/">on my own mod site</a>, where downloads are available for a tiny fee.</p><p>There&#8217;s a key piece of infrastructure to make such an independent, granular model work. It&#8217;s the killer use case for Solana, an ultra-fast blockchain that has fees even more fractionally tiny than $0.015.</p><p>Whereas most modders rely on Patreon (subscriptions), I charge just 0.005 SOL per download, which (at the current time of writing) is 40 cents. The fee for the transaction is 0.00008 SOL, which is $0.0064. The fee wouldn&#8217;t be higher if I charged more.</p><p>Of course, there&#8217;s a variety of methods by which a business model like this could be accomplished. If one prefers a more internal approach, this can be implemented using a company&#8217;s own internal currency, and priced entirely through <a href="https://klovell.substack.com/p/game-designers-love-xml">product-driven observable systems</a> that give ultimate flexible control without the engineering lift.</p><p>On the opposite end of the spectrum for decentralized network effects, the SOL-based system could be integrated into existing ad bidding frameworks, allowing the user to be an active participant in their own ad auction. If the user wins, they aren&#8217;t shown an ad. This would close ads/subscription pricing gap in its totality, through the power of efficient markets.</p><p>Since everything is ultimately worth what its purchaser will pay for it, prioritizing market efficiency is the ultimate method for defining value. Let the invisible hand leverage your product-market fit.</p>]]></content:encoded></item><item><title><![CDATA[Like shooting Barrels in a Fish]]></title><description><![CDATA[Use cases for the Fisheye Lens]]></description><link>https://entanglement.games/p/like-shooting-barrels-in-a-fish</link><guid isPermaLink="false">https://entanglement.games/p/like-shooting-barrels-in-a-fish</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 24 Mar 2026 16:30:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d7261ccc-fdcd-44ee-ab46-a606baee0e89_1960x1104.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>As gamers, we&#8217;ve had extraordinary access to incredible graphics power for decades now. Primarily, this graphics power has been used in the pursuit of hyperrealism. While this is a worthwhile pursuit, I think it&#8217;s a rather oversaturated one. Today in conclusion, I&#8217;m citing this as the primary reason I chose to develop a fisheye lens, despite its very valid <a href="https://klovell.substack.com/p/vibe-engineering-graphics-pipelines">inspiration from Homestar Runner</a>. I&#8217;m pursuing the question: what else can we do creatively with this extraordinary graphics power every gamer has in their PC?<br><br>The best sci-fi development inspiration comes from books, and one of my all-time favorites is the <a href="https://www.goodreads.com/series/191900-the-murderbot-diaries">Murderbot Diaries</a> series. The series follows the internal life of a human-bot construct designed to the narrow specifications of being extremely well suited to security roles. This book series is now a &#8220;serial&#8221; on Apple TV. Watching it, I was struck by how TV as a medium can&#8217;t translate the internal perceptive that makes Murderbot&#8212;as not a quite a human, not quite a bot&#8212;such an interesting construct.</p><p>It&#8217;s shown that Murderbot always looks slightly to the side of the head of anyone its talking to. What is not shown: typically in conversation Murderbot is not looking through its eyes at all. Given that it is security-specialized, it integrates whatever cameras are in its vicinity straight into in own perspective, and whenever possible, it will choose to look through the cameras to observe its own conversation. This sounds dissociative, but given how cameras might as well be its own body, it&#8217;s really not. (Cyberpunk 2077&#8217;s netrunner mechanics <a href="https://www.reddit.com/r/cyberpunkgame/comments/1rbh9b0/if_you_look_through_cameras_during_the_pl_mission/">do a pretty decent job at depicting this</a>, though I get the feeling it could be explored more deeply&#8212;and pushed further.)</p><p>But what causes Murderbot to be so uncomfortable looking at people head on in the first place? What might the difference in perspective be? Here&#8217;s where we tie it back to my fisheye lens, and how we might be able to replicate the perspective described in the book through environmental storytelling in gaming.</p><p>Fisheye lenses might offer a security bot&#8212;in its main camera from which it aims weapons&#8212;a tactical advantage. They widen the field of view past what is normal from a human perspective, and provide extra detail within the closer, narrower field. It might be great for first person shooter mechanics. It also is less specialized&#8212;and could provide some weird dynamics&#8212;interpersonally. You can see it back in <a href="https://www.youtube.com/watch?v=hHcyJPTTn9w&amp;list=RDhHcyJPTTn9w&amp;start_radio=1">Missy Elliot&#8217;s video</a>, which is clearly designed to be a little freaky. If every conversation felt as up close as this&#8212;wouldn&#8217;t that make you uncomfortable?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LEh9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LEh9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 424w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 848w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 1272w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LEh9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png" width="1456" height="1093" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1093,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2151309,&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://klovell.substack.com/i/187349533?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.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_!LEh9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 424w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 848w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.png 1272w, https://substackcdn.com/image/fetch/$s_!LEh9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd743e2e7-63da-4e77-8c6f-1438945c7478_1534x1152.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>Anyway, to truly test if this dynamic works, I need to create a shooter prototype running through my fisheye lens. I&#8217;d test 1) if you can shoot accurately, and 2) if I can leverage the lens to add some exaggerative flair to a close-up situation.</p><p>Thus, I created the game <a href="https://uuqv.itch.io/barrels-in-a-fish">Barrels in a Fish</a>. While you yourself are trapped in a barrel-shaped environment, barrels fall increasingly quickly from the sky. If you shoot the barrels, a myriad of random fish will explode out of them, gradually filling your view with close-ups of (dead) fish.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ny3B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ny3B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 424w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 848w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 1272w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ny3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png" width="1226" height="710" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:710,&quot;width&quot;:1226,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:894389,&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://klovell.substack.com/i/187349533?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.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_!Ny3B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 424w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 848w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.png 1272w, https://substackcdn.com/image/fetch/$s_!Ny3B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8236736b-62d9-41c0-84e8-1d16df6a361d_1226x710.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>I managed to integrate my fisheye shader, <a href="https://klovell.substack.com/p/cubemaps">cubemaps</a> and all, with a godot game via cpp extension, which is pretty neat. The extension itself ended up significantly simpler than building it from scratch in vulkan was, although getting it to compile to wasm correctly&#8212;enabling it to be playable on web&#8212;involved a bit of trial and error.</p><p>I think the game yielded positive results for my hypotheses: I can still shoot accurately, and the lens made what was already an amusingly weird mechanic that much more impactful.<br><br>It also nicely closes a loop from the lens&#8217; originally cited inspiration&#8212;we answer the question posed by Homestar: <a href="https://youtu.be/rbvxlvSIIww?si=3TUibuggejpnzuXD&amp;t=155">what happens if you point it at a real fish eye</a>?</p>]]></content:encoded></item><item><title><![CDATA[Cubemaps]]></title><description><![CDATA[I know we talked about mimicking the real-life physics to achieve the fisheye lens effect. I suppose to that affect I could say there&#8217;s no rule that says the first pass has to be ready for human consumption. Nature doesn&#8217;t have to be either!]]></description><link>https://entanglement.games/p/cubemaps</link><guid isPermaLink="false">https://entanglement.games/p/cubemaps</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 10 Mar 2026 15:48:52 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iRJ7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I know we talked about <a href="https://klovell.substack.com/p/lens-distortion-and-fragment-shaders">mimicking the real-life physics to achieve the fisheye lens effect</a>. I suppose to that affect I could say there&#8217;s no rule that says the first pass has to be ready for human consumption. Nature doesn&#8217;t have to be either!</p><p>Last week we proved how <a href="https://open.substack.com/pub/klovell/p/lens-distortion-and-fragment-shaders?utm_campaign=post-expanded-share&amp;utm_medium=web">it would be impossible to create a second pass that could sample a 2D first pass and achieve any semblance of quality</a>. The view angle gets too steep:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N1yt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N1yt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 424w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 848w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png" width="1456" height="769" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:769,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!N1yt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 424w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 848w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.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>Therefore, the only place we can tackle this is in the first pass. How could we improve the viewing angle? Well, we could bend the projection!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!392r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!392r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 424w, https://substackcdn.com/image/fetch/$s_!392r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 848w, https://substackcdn.com/image/fetch/$s_!392r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 1272w, https://substackcdn.com/image/fetch/$s_!392r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!392r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png" width="1236" height="854" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bac62a31-1279-4740-8aff-d489897d7e47_1236x854.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:854,&quot;width&quot;:1236,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44787,&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://klovell.substack.com/i/190461649?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.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_!392r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 424w, https://substackcdn.com/image/fetch/$s_!392r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 848w, https://substackcdn.com/image/fetch/$s_!392r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.png 1272w, https://substackcdn.com/image/fetch/$s_!392r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbac62a31-1279-4740-8aff-d489897d7e47_1236x854.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>That sounds complicated though. (I realize I&#8217;m saying that after taking derivatives of trigonometric functions, but if nothing else we want to avoid the computer doing extra work!) What if&#8230;we just put in two sharp bends instead?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iRJ7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iRJ7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 424w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 848w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 1272w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iRJ7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png" width="1456" height="1127" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1127,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:83994,&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://klovell.substack.com/i/190461649?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.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_!iRJ7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 424w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 848w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.png 1272w, https://substackcdn.com/image/fetch/$s_!iRJ7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F12c5654b-2a96-40bf-abb5-a0f8558b89bb_1542x1194.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>Add above and below to the equation and this, my friends, is the beginnings of a <a href="https://en.wikipedia.org/wiki/Cube_mapping">cubemap projection</a>! Instead of mapping things continuously, anything in the first pass that would fall out of a (half) viewing angle &#952; of 45&#176; is mapped onto the next square.</p><p>Our widest viewing angle, the trickiest place to sample, is now the corner of our cube. Our sample rate of change (that trigonometric derivative) sec&#178;(&#952;), looking at the corner of our cube at 45&#176; (a.k.a. &#960;/4), does not approach infinity&#8212; sec&#178;(&#960;/4) is simply&#8230;2!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wHDx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wHDx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 424w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 848w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1272w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png" width="442" height="262" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:262,&quot;width&quot;:442,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!wHDx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 424w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 848w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1272w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.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 at worst, we&#8217;ll need to sample at two times the sample rate at dead center. Perhaps a little challenging, but much more manageable than infinite.</p><p>And that&#8217;s what got a rendering 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_!8eOT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8eOT!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" width="800" height="450" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!8eOT!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.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>To look 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_!cIuD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cIuD!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 424w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 848w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif" width="800" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75413812-e4df-49b0-b6b4-32433359add8_800x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!cIuD!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 424w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 848w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.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>And with that out of the way, we&#8217;ll be able to move on to talking about the fisheye lens math itself!</p>]]></content:encoded></item><item><title><![CDATA[When 2D Projections Become Unviable]]></title><description><![CDATA[Nyquist Sampling Theorem!]]></description><link>https://entanglement.games/p/when-2d-projections-become-unviable</link><guid isPermaLink="false">https://entanglement.games/p/when-2d-projections-become-unviable</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 03 Mar 2026 14:44:05 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!N1yt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Last week we talked about how to create a <a href="https://klovell.substack.com/p/lens-distortion-and-fragment-shaders">double-process rendering pipeline</a> to create a distortion lens effect. But we still had a glaring problem: the quality is terrible!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8eOT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8eOT!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" width="800" height="450" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&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="" srcset="https://substackcdn.com/image/fetch/$s_!8eOT!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.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>Particularly in the texture! Choosing one with lots of straight lines really highlighted the problem&#8212;downsampled straight line patterns have a tendency to create moir&#233; patterns, consistent with those typically alleviated by applying <a href="https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem">Nyquist Sampling Theorem</a>. The theorem boils down simply: to accurately capture a signal, sample at 2x the highest frequency.</p><p>The "frequency" here is spatial&#8212;how fast details change across the screen. The position on the screen per the view angle is determined by tan(&#952;):</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!N1yt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!N1yt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 424w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 848w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png" width="1456" height="769" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:769,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121809,&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://klovell.substack.com/i/189615144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.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_!N1yt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 424w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 848w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.png 1272w, https://substackcdn.com/image/fetch/$s_!N1yt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F252328f0-7295-49d7-a5b4-bc458caafadb_1984x1048.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>As the angle increases, the rate at which the position on the 2D projection changes would be the derivative of tan(&#952;)&#8212;sec&#178;(&#952;). Plug that into the calculator with, for example, 80&#176;&#8212;you&#8217;ll find that the rate of change is ~33&#8212;in other words, one degree of change at 80&#176; spreads across 33x the pixels. At 2x according to Nyquist, you&#8217;d need 66x the pixels!</p><p>Of course, it gets worse. Considering we&#8217;re doing a fisheye lens, we&#8217;re going to want to approach a field of view near 180&#176;&#8212;and in the graph for sec&#178;(&#952;), you can see that as you approach &#960;/2 (90&#176; for half the total FOV), we approach infinity:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wHDx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wHDx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 424w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 848w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1272w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png" width="442" height="262" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:262,&quot;width&quot;:442,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:44509,&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://klovell.substack.com/i/189615144?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.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_!wHDx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 424w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 848w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.png 1272w, https://substackcdn.com/image/fetch/$s_!wHDx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e3fed22-3b9d-46ef-877a-19f1704c98fe_442x262.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>And good luck getting enough samples for infinity, twice!</p><p>It&#8217;s clear that in order to sample for our fisheye lens properly we&#8217;re going to need a different projection for our first pass. What&#8217;ll we do instead? (You&#8217;ll find out next week!)</p>]]></content:encoded></item><item><title><![CDATA[Lens Distortion and Fragment Shaders]]></title><description><![CDATA[Using VR Correction Techniques for a Fisheye Lens]]></description><link>https://entanglement.games/p/lens-distortion-and-fragment-shaders</link><guid isPermaLink="false">https://entanglement.games/p/lens-distortion-and-fragment-shaders</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 24 Feb 2026 15:58:54 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!d-Ae!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a href="https://klovell.substack.com/p/vibe-engineering-graphics-pipelines">As I promised in the last article</a>, I&#8217;ll be discussing one of the crucial components in creating a fisheye lens using the Vulkan Graphics Library. We&#8217;ll talk more about the math behind the distortion, but for now (for the sake of iterative methodology), we need to know where to apply this distortion. That way, we can observe and improve the distortion math.</p><p>Each basic graphics pipeline has two points for transforming 3D positions into 2D screen coordinates: a vertex shader and a fragment shader. The vertex shader runs once for every vertex (corner point) in your 3D geometry. After the GPU figures out which pixels on screen are covered by a triangle, the fragment shader runs once per each of these triangles. Its job is to determine the color of that pixel.</p><p>My quadrilateral tax paper is made of 4 vertices and 2 triangle fragments:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d-Ae!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d-Ae!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 424w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 848w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 1272w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d-Ae!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png" width="1158" height="776" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:776,&quot;width&quot;:1158,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60906,&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://klovell.substack.com/i/188269882?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.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_!d-Ae!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 424w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 848w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.png 1272w, https://substackcdn.com/image/fetch/$s_!d-Ae!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa37ab44-f6d9-4d6a-ab0c-f5dbf07bd0d0_1158x776.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>When I try to apply distortion in the vertex shader, it gets the positioning right. But because it&#8217;s acting only on the vertices, when it comes to the interpolation between them, we still get straight 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_!VgiX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VgiX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 424w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 848w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 1272w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VgiX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png" width="1284" height="776" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:776,&quot;width&quot;:1284,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:60753,&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://klovell.substack.com/i/188269882?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.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_!VgiX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 424w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 848w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.png 1272w, https://substackcdn.com/image/fetch/$s_!VgiX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ab93cd9-ddc1-41db-8645-8f4f0854705f_1284x776.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>A similar issue happens in the fragment shader. While the distortion looks sufficiently &#8220;bulbous,&#8221; well&#8230;it only applies per fragment:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oAjD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oAjD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 424w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 848w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 1272w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oAjD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png" width="1158" height="776" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/758449e1-74e6-458e-919d-07d61017a101_1158x776.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:776,&quot;width&quot;:1158,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:56937,&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://klovell.substack.com/i/188269882?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.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_!oAjD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 424w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 848w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.png 1272w, https://substackcdn.com/image/fetch/$s_!oAjD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F758449e1-74e6-458e-919d-07d61017a101_1158x776.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>(I wish I had made recordings of these states&#8230;let that be a lesson in why you don&#8217;t hide from your work until you get it right.)</p><p>If we were to mimic the real-life physics, what we&#8217;d need here is a finished view of the whole, and to then apply the distortion to the whole. So what we&#8217;ll do is set up <em>two</em> graphics pipelines. The first generates a fully rendered image, the second takes in that fully rendered image as a fragment and applies the fisheye distortion.</p><p>This process is really similar to the established practice of correcting VR lens distortion. VR headsets use wide-angle lenses placed close to the screen to create a sense of immersion. These lenses bend light in a way that causes pincushion distortion&#8212;straight lines bow inward, and the image stretches more toward the edges than the center. If you rendered a normal scene and just displayed it, it would look warped.</p><p>The trick is to intentionally apply the inverse distortion&#8212;barrel distortion&#8212;to the rendered image before it hits the lens. The lens then un-distorts it back. We&#8217;ll simply swap out barrel distortion for fisheye:<br><br>I did at least make a recording after I got the dual pipeline approach working!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8eOT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8eOT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif" width="800" height="450" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:450,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:4211436,&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://klovell.substack.com/i/188269882?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.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_!8eOT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 424w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 848w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.gif 1272w, https://substackcdn.com/image/fetch/$s_!8eOT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7e93c77e-81ef-4ff2-92a7-5f0b64fb102a_800x450.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>You will however notice that the texture quality is terrible! But that&#8217;s a topic for next week!</p>]]></content:encoded></item><item><title><![CDATA[Vibe Engineering Graphics Pipelines]]></title><description><![CDATA[The Fish Eye Lens in Vulkan]]></description><link>https://entanglement.games/p/vibe-engineering-graphics-pipelines</link><guid isPermaLink="false">https://entanglement.games/p/vibe-engineering-graphics-pipelines</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 09 Feb 2026 14:31:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/42feaae7-4976-4e23-9268-1d3eeb1704ae_1934x1228.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Since this <a href="https://www.youtube.com/watch?v=rbvxlvSIIww">Homestar Runner</a> short came out over ten years ago, you wouldn&#8217;t just say it&#8217;s lived in my mind rent free&#8212;it&#8217;s more like it has squatter&#8217;s rights.</p><p>Within this #1 Jam, Strong Bad asserts that you can make anything look cool with a Fish Eye Lens; but this is more than just memes, it&#8217;s established &#8220;Vibe Engineering&#8221; practice. Vibe Engineering (distinct from Vibe Coding) has one of its most important empirical demonstrations in Missy Elliot&#8217;s classic video for <a href="https://www.youtube.com/watch?v=hHcyJPTTn9w&amp;list=RDhHcyJPTTn9w&amp;start_radio=1">The Rain</a>, where she utilized the very technique that Strong Bad emulates. Through this lens, she manages make a costume that is essentially an inflated garbage bag an iconic exploration of dynamic movement.</p><p>There&#8217;s one more thing in particular to note that Strong Bad and Coach Z mention: fish eyes used to be expensive, but now? Not so much. Indeed, many creative works have groundbreaking creative works have grown out of the technology to create them becoming cheaper and more accessible. In a categorical line of creative thinking, I&#8217;ve been exploring how to use the massive amount of modern graphics computing power for more creative game dynamics than just hyperrealism.</p><p>Thus, in the name of Vibe Engineering, I have sought out to create a fish eye lens using the Vulkan graphics library.</p><p>But before I even began to work on my new lens, I would need something to look at. Strong Bad and Coach Z provide a plethora of examples about how to make anything look cool, including the most innocuous items: tan pants, country dish towels&#8230;and tax papers. Since it&#8217;s Tax Season, I thought I&#8217;d use the latter example to add a little festivity.</p><p>As our starting point, here&#8217;s what a plain rendering of one such tax paper looks like:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AyCH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AyCH!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 424w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 848w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 1272w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AyCH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif" width="800" height="595" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:595,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:5310221,&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://klovell.substack.com/i/186417505?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.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_!AyCH!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 424w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 848w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.gif 1272w, https://substackcdn.com/image/fetch/$s_!AyCH!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F71da20a0-e585-45bc-a558-b6becb2cdd9e_800x595.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>I will diving deeper into the challenges of creating a fisheye lens in Vulkan over the next couple weeks. For an overview: it uses a similar technique to VR lens correction. We have two separate graphics pipelines: one to render the scene, and one to apply distortion over the full render finished previously. Using a cubemap prevents excessive quality loss over the parts of the model with enlarged detail. You can view the github repository <a href="https://github.com/UuqV/vulkan-angles/tree/main">here</a>. But for now&#8212;behold!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cIuD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cIuD!,w_424,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 424w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_848,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 848w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1272,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_webp,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif" width="800" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/75413812-e4df-49b0-b6b4-32433359add8_800x600.gif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:11189691,&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;:false,&quot;internalRedirect&quot;:&quot;https://klovell.substack.com/i/186417505?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.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_!cIuD!,w_424,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 424w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_848,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 848w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1272,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 1272w, https://substackcdn.com/image/fetch/$s_!cIuD!,w_1456,c_limit,f_auto,q_auto:good,fl_lossy/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F75413812-e4df-49b0-b6b4-32433359add8_800x600.gif 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>What do you think? Is it cooler?</p>]]></content:encoded></item><item><title><![CDATA[Destroy your iFrames]]></title><description><![CDATA[When you run a site with ads, it can be like running Chrome with too many tabs open.]]></description><link>https://entanglement.games/p/destroy-your-iframes</link><guid isPermaLink="false">https://entanglement.games/p/destroy-your-iframes</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Thu, 05 Feb 2026 20:23:23 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ea372ffb-9dec-40b0-afe4-0f2d30a5945b_612x417.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When you run a site with ads, it can be like running Chrome with too many tabs open. You&#8217;re likely loading lots of hidden iFrames. To keep your site sane, it&#8217;s important to do something when these frames have outlived their use.</p><h2>What is an iFrame?</h2><p>An iframe is effectively a page within a page. It loads a specified url, which can come from any third party. Each iframe includes a separate layout engine, event system, and javascript heap, everything a different tab in your browser would. You can imagine this can get pretty performance heavy.</p><p>Despite their performance issues, iFrames can quite good for isolation, particularly if sandboxed. They can&#8217;t read content outside of themselves, which is why they&#8217;re used so predominantly for third party content like ads.</p><h2>Hidden Data</h2><p>While iFrames are originally intended to be viewable on the page, because of their isolating properties, they&#8217;re very typically used by third party tools to manage their own data. These iFrames are hidden from view typically by setting their width and height to 0 and/or using &#8220;display: none&#8221;.</p><p>But how necessary is this data? To understand this better, let&#8217;s examine a particularly predominant use of hidden iFrames: &#8220;usersync&#8221; frames.</p><p>Advertisers use usersync frames to sync anonymized identifier cookies with other partners. Company A knows you as "user123" while Company B knows you as "user789," and they need a way to realize these IDs refer to the same person.</p><ul><li><p>Your browser loads the iframe from the ad exchange&#8217;s domain</p></li><li><p>The ad exchange reads its own cookie (e.g., &#8220;user123&#8221;) from your browser</p></li><li><p>The iframe redirects to the partner&#8217;s domain</p></li><li><p>The partner reads their own cookie (e.g., &#8220;user789&#8221;) and creates a mapping: exchange_id=user123 &#8596; their_id=user789</p></li><li><p>Both companies now know these IDs represent the same user</p></li></ul><p>You can typically identify them by their sandbox parameters: </p><p><code>sandbox=&#8221;allow-scripts allow-same-origin&#8221;</code></p><p>The thing is, this process is typically finished fairly quickly. Unfortunately, these frames aren&#8217;t cleaned up automatically after they&#8217;ve served their purpose. You can do this yourself fairly easily however.</p><p>Have your page wait ~60 seconds, then use some classic jQuery to search for the signatures and remove them.</p><p>You can use the sandbox parameters above to identify usersync frames.</p><p>As for the rest of them, it&#8217;s tricky to say what every third party is doing in these iFrames (this is partly the point!) so, mainly this must be approached through experimentation.</p><p>In my experience, I&#8217;ve observed no ill effects in the data from simply cleaning up every hidden frame. On the flip side, this has had incredible effects on memory usage for longer running pages, reducing the load by 40%!</p><p>So, what are you waiting for? Smash your iFrames today!</p>]]></content:encoded></item><item><title><![CDATA[Iterating Quickly with A/B Tests]]></title><description><![CDATA[Infrastructure for Fast Validation]]></description><link>https://entanglement.games/p/iterating-quickly-with-ab-tests</link><guid isPermaLink="false">https://entanglement.games/p/iterating-quickly-with-ab-tests</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 26 Jan 2026 14:59:46 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ad9a12eb-67e6-4395-a120-4242ada361ce_1920x1080.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You start with a single test. This leads to two possible states in your code.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!grJP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!grJP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 424w, https://substackcdn.com/image/fetch/$s_!grJP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 848w, https://substackcdn.com/image/fetch/$s_!grJP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 1272w, https://substackcdn.com/image/fetch/$s_!grJP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!grJP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png" width="1084" height="544" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:544,&quot;width&quot;:1084,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:23990,&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://klovell.substack.com/i/185594113?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.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_!grJP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 424w, https://substackcdn.com/image/fetch/$s_!grJP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 848w, https://substackcdn.com/image/fetch/$s_!grJP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.png 1272w, https://substackcdn.com/image/fetch/$s_!grJP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ee9b2d0-8122-4e25-98a1-dd3e9d676b1a_1084x544.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>But say you add just two more:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!IFUZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!IFUZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 424w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 848w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 1272w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!IFUZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png" width="1456" height="976" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:976,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:105132,&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://klovell.substack.com/i/185594113?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.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_!IFUZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 424w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 848w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.png 1272w, https://substackcdn.com/image/fetch/$s_!IFUZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F00a76094-606c-4871-9cad-4be7d735c64e_1506x1010.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>The number of possible code states begins to expand exponentially, 2^n to be precise, where n is the number of tests. That&#8217;s 2^n code states to manage, test, and monitor. And within each of these categories unique challenges are presented:</p><ul><li><p><strong>Management &#8212;</strong> A/B tests encoded with feature flags are often ramped up manually, over long periods of time. Your organization has to remember to track them, and you&#8217;ll have to remember to clean them up when you&#8217;re done.</p></li><li><p><strong>Testing &#8212; </strong>Unit and Smoke tests by default usually test the &#8220;control&#8221; side of the test&#8212;the side with no experimental changes. You have to make sure to code in variations for each test, and that undermines a key value in automated testing: testing regressions on the periphery.</p></li><li><p><strong>Monitoring &#8212; </strong>With similar challenges to unit testing, monitoring also comes with a scale challenge. Monitors are typically built to detect drastic changes in traffic or behavior. If you&#8217;re testing on a small portion of traffic, drastic effects in your variations may not be visible to your monitors immediately.</p></li></ul><p>So what can we do about this?</p><p>If you have continuous deployment, site traffic is likely already directed to a load balancer. When you make a new deploy, your load balancer switches from your old build to your new build.</p><p>We can use the load balancer to instead move traffic gradually from the old version of the site onto the new version.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kFif!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kFif!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 424w, https://substackcdn.com/image/fetch/$s_!kFif!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 848w, https://substackcdn.com/image/fetch/$s_!kFif!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 1272w, https://substackcdn.com/image/fetch/$s_!kFif!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kFif!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png" width="1456" height="961" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:961,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:129318,&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://klovell.substack.com/i/185594113?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.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_!kFif!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 424w, https://substackcdn.com/image/fetch/$s_!kFif!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 848w, https://substackcdn.com/image/fetch/$s_!kFif!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.png 1272w, https://substackcdn.com/image/fetch/$s_!kFif!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fef860e47-3dcf-4f35-b26d-27d504f44c44_1658x1094.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 is called a &#8220;canary deploy,&#8221; and it can be done for every continuous deployment. This offers several advantages compared to feature flag A/B tests:</p><ul><li><p>They come with every deploy without extra effort for developers</p></li><li><p>They are ramped up quickly and cleaned up just as fast</p></li><li><p>Because divergent states aren&#8217;t allowed to compound, they are simpler to test and monitor</p></li></ul><p>Of course, there are some times when you&#8217;ll want a more traditional A/B test. It&#8217;s likely that a few commits will go out with each deploy; if you require a high level of specificity, you&#8217;re better off using a feature flag. This often coincides with when you are testing a longer running feature, and are not just checking for big changes but for specific, incremental effects.</p><p>Nevertheless, there&#8217;s huge advantage to integrating canary deploy A/B tests into your CI/CD pipeline. As much as possible, we shouldn&#8217;t add special testing and monitoring infrastructure with every new feature&#8212;it should come baked in with every new feature automatically. In this way, we can iterate as quickly as possible without compromising quality or integrity.</p>]]></content:encoded></item><item><title><![CDATA[Big Data for Ads]]></title><description><![CDATA[and the Real Cost of Latency]]></description><link>https://entanglement.games/p/big-data-for-ads</link><guid isPermaLink="false">https://entanglement.games/p/big-data-for-ads</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Tue, 20 Jan 2026 18:23:02 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iud-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F144c49cf-6f1d-495f-b4e9-5f5db0ee3376_403x403.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To switch things up a little, I thought I&#8217;d talk about a server-side aspect of Ads Performance for a change. If you do ads right, you can easily consume tons of data, perhaps even more than the rest of your company combined. That and there are real demands for real-time on the ads side of things; you want responsive user targeting, to know whether a particular campaign is performing, or whether you&#8217;ve suddenly and dramatically lost revenue. How do you drink from this firehose of data, and do it in a way that is both accurate and cost-efficient?</p><h2>Introducing Publish/Subscribe for Microservices</h2><p>Everyone loves to reach for microservices, but in practice implementing them at your company can be an uphill battle. More than likely, it&#8217;s just that you&#8217;re missing one crucial piece.</p><p>Last week I talked about <a href="https://open.substack.com/pub/klovell/p/game-designers-love-xml?utm_campaign=post-expanded-share&amp;utm_medium=web">event-driven systems</a>. In contrast to typical REST systems, that are stateless and require &#8220;pulling&#8221; data at a client&#8217;s request, event-driven systems &#8220;push&#8221; data to services that consume them.</p><p>This model is incredibly useful in high throughput real-time systems, largely due to the dependency inversion I discuss in the article linked above. As Tim Burglund demonstrates in his <a href="https://www.youtube.com/watch?v=06iRM1Ghr1k">Apache Kafka video</a>, having a push model and stateful log naturally begets the microservices model. Suddenly, microservices can be a natural consequence of engineers leveraging a particularly useful piece in their architecture stack, not something that needs to be constantly enforced.</p><p>But crucially this also facilitates a particular degree of statefulness amongst distributed systems. In addition to the raw event log Kafka automatically records, this also enables us to run real-time aggregate jobs at scale, which are highly useful for ads metrics.</p><h2>The Real Cost of Latency</h2><p>At high scale, the real cost is not individual message latency, but how efficiently a system can process large volumes of events. Architectures that support batching and parallel consumption can sustain far higher throughput with less infrastructure.</p><p>Log-based systems like Kafka are designed to process events in large batches, which reduces per-event overhead and allows real-time pipelines to scale efficiently. Systems that emphasize per-message delivery and acknowledgements can require more concurrent consumers to keep up as volume grows, increasing operational cost.</p><h2>Conclusion</h2><p>Running a successful ads business necessitates highly accurate real-time metrics at scale. The technology is there, and it&#8217;s open source. Adopting these technologies for the revenue side of the business is also a perfect moment for revenue teams to lead great architecture decisions company-wide.</p>]]></content:encoded></item><item><title><![CDATA[Game Designers Love XML]]></title><description><![CDATA[Product Managers Will Love SDUI]]></description><link>https://entanglement.games/p/game-designers-love-xml</link><guid isPermaLink="false">https://entanglement.games/p/game-designers-love-xml</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 12 Jan 2026 14:17:30 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6a194b96-c1b9-4658-96fb-7337ba66ffd4_1000x600.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Imagine things with a bit of an inversion. Once the initial, bare-bones system is mapped out by the product team, development begins immediately. Once development has a working system, design or product then goes in and tunes the system iteratively. You have a decent boilerplate system, and the design may be 80-90% there. Development starts immediately, you end up with a well-tuned end product.</p><p>If you&#8217;ve ever poked around with game modding, you might notice that many games provide a fantastic amount of leverage to mod with without ever having to touch the code. How do they do this? Through the magic of XML tuning files.</p><h2>What can Web learn from Games?</h2><p>XML tuning files have a close analog in server-driven UI (SDUI). SDUI typically uses JSON to define how a component looks. For example:</p><pre><code>{
  "type": "Card",
  "title": "Upgrade",
  "cta": { "label": "Buy" }
}</code></pre><p>This, however, can go further. In addition to styling, you can also encode your data system to pick up queues for interactivity.</p><p>I&#8217;ve written <a href="https://uuqsims.com/">quite a few game mods</a> that encode a complex interaction chain: a particular effect is triggered, which on an auto-resolve curve; i.e., the effect is taken off after a given amount of time. On resolution, it presents a different effect, which in turn has its own auto-resolution. I didn&#8217;t have to touch the game scripts at all for these; these gameplay effects can be encoded entirely through XML.</p><p>To illustrate an example for the Web, imagine you knew you wanted to reward users &#8220;coins.&#8221; You&#8217;re not sure exactly how you want to grant or use those coins yet (economies are complex), and you want to experiment iteratively. If you have components specified through data, you can also define a field that specifies a number of coins to grant&#8212;on any component you want.</p><pre><code><code>{
  "type": "Button",
  "title": "Upgrade",
  "cta": { "label": "Buy" },
  "coins": 100
}</code></code></pre><p>You could go even further and specify a level of randomness:</p><pre><code><code>{
  "type": "Button",
  "title": "Upgrade",
  "cta": { "label": "Buy" },
  "coins": 100,
  "randomness": 10 // granted +/- 10 the amount of coins listed above
}</code></code></pre><p>Or even specify a level of compounding:</p><pre><code><code>{
  "type": "Button",
  "title": "Upgrade",
  "cta": { "label": "Buy" },
  "coins": 100,
  "randomness": 10 // granted +/- 10 the amount of coins listed above
  "gain": x * 1.01 // gain 1% of the initial value each subsequent time
}</code></code></pre><h2>Decoupled, Event-Driven, Config-Driven Systems</h2><p>When everything is specified in data files, your system becomes very easily auditable. Just as these data files are parsed into your code, they can be parsed into a configuration system where you can get an overview of each effect. For example, if you, as a product manager, wanted to get an overview of each interaction on your site that supports granting coins, that&#8217;s something that&#8217;s easily readable like a spreadsheet.</p><p>But how exactly do you parse and support these data files within your code as a developer? Through event-driven architecture. I once built a poker game with Solana blockchain rails that <a href="https://github.com/UuqV/sol-poker/blob/main/client/src/clientSocket.js">used websockets as the primary communication method</a> between client and server. Contrasted to REST APIs, websockets are a push-pull model that require you to specify an event type for each event sent&#8212;such is event driven architecture. These types are easily leveraged in json files to enforce a data specification.</p><p>And using event-driven architecture has one massive advantage in particular&#8212;decoupling. When an event &#8220;producer&#8221; (e.g. a button is clicked) and an event &#8220;consumer&#8221; (e.g. a wallet counting how many coins you have) are decoupled, they do not know about each other. You can modify, redeploy, or even delete a consumer without touching the producer, and vice versa. This sharply reduces coordination cost and regression risk.</p><p>Consider an e-commerce product where the core checkout service emits an event called &#8220;OrderPlaced.&#8221;</p><p>The checkout team owns only one responsibility: validate payment, create the order, and publish that event. They do not know or care what happens next.</p><p>Design and product want to experiment with several things at once:<br>&#8226; a new post-purchase email flow<br>&#8226; a &#8220;people also bought&#8221; recommendation widget<br>&#8226; a loyalty points system<br>&#8226; a fraud-scoring model</p><p>In a tightly coupled system, each of those would require the checkout engineers to add logic, call new APIs, deploy new code, and take on risk. Product and design would have to file tickets, wait for sprint planning, and negotiate priorities just to run an experiment.</p><p>Decoupling vastly improves system extensibility. New behavior is added by subscribing to existing events rather than modifying existing code paths. So, as a designer or a product manager, you can attach a new analytics pipeline, billing rule, or notification system without having to have engineers change the service that emits an event &#8220;PlaceOrder.&#8221;</p><h2>Conclusion</h2><p>Data config-driven systems can fulfill a product team&#8217;s wildest dreams&#8212;and event-driven architecture is the engineering backbone that makes it happen. It&#8217;s embraced in many high-performance applications&#8212;embracing it can allow Web companies to scale their teams&#8217; velocity to unprecedented levels, and provide extraordinary leverage for the business.</p>]]></content:encoded></item><item><title><![CDATA[Server-Side rendering doesn't break your ads. It makes them better than ever before.]]></title><description><![CDATA[For a variety of reasons, everyone wants their site to perform well.]]></description><link>https://entanglement.games/p/server-side-rendering-doesnt-break</link><guid isPermaLink="false">https://entanglement.games/p/server-side-rendering-doesnt-break</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 05 Jan 2026 20:14:15 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!iud-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F144c49cf-6f1d-495f-b4e9-5f5db0ee3376_403x403.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>For a variety of reasons, everyone wants their site to perform well. A performant site often correlates directly with quantifiable outcomes&#8212;greater user conversion, better ranking with search engines, etc. However, ultimately everyone wants this to translate into real revenue, and when we first use the tools most suited for this&#8212;namely, static site generators&#8212;we often see ad revenue tank.</p><p>What happens here? Well, thankfully it&#8217;s nothing insurmountable. In fact, leveraging server-side rendering unlocks some of the most powerful architectures for improving both your page performance and your ad auction performance.</p><h2>Loading Your Scripts</h2><p>Third party ads libraries such as Prebid.js, Google Publisher Tag, and TAM are loaded with script tags&#8212;this is in part because they attach globally to your browser&#8217;s window object.</p><p>It&#8217;s useful then to know with precision when exactly the window object is created in a Next.js lifecycle. Often advice in this area assumes you should wait post-hydration to allow scripts to capture the window object, but the window object is available after the first server-side render.</p><p>Thus, when you first start using Next.js with ads, you might receive the advice to use &#8220;afterInteractive&#8221; on all your script tags. This isn&#8217;t strictly necessary. In fact, if you don&#8217;t load your scripts as &#8220;beforeInteractive,&#8221; you could be missing out on revenue, since loading the scripts sooner means your ads can load sooner.</p><h2>Command Queues</h2><p>With GPT, instead of waiting for hydration, you can use the &#8220;defer&#8221; keyword on your script tag to ensure that execution waits until just after HTML parsing. </p><pre><code><code>&lt;script defer src="gpt.js" /&gt;</code></code></pre><p>You can then predefine command queues:</p><pre><code>  window.googletag = window.googletag || {};
  googletag.cmd = googletag.cmd || [];</code></pre><p>This is the exact formula googletag uses internally to attach to the window object. Once the script finishes loading, it will use what&#8217;s there, and attach to the window object internally, so there won&#8217;t be any synchronization issues. You&#8217;re then free to use the `async` keyword:</p><pre><code><code>&lt;script async src="gpt.js" /&gt;</code></code></pre><p>This means you can attach commands to the command queue even if your scripts aren&#8217;t loaded yet. The command queue allows you to continue setup functions before the script is fully loaded:</p><pre><code>googletag.cmd.push(function() {
  googletag.defineSlot(...);
});</code></pre><p>This is <strong>dependency inversion</strong>, and it comes up repeatedly to resolve tough asynchronous execution knots. Interestingly, this comes up a lot in GPU programming as well&#8212;if your pipelines have a queue to pop commands off from, it means the pipeline can consume it as soon as it decides it&#8217;s ready, instead of waiting for something external that presumes it isn&#8217;t.</p><h2>Single Request Architecture</h2><p>This dependency inversion enables us to leverage one particularly powerful googletag feature&#8212;Single Request Architecture:</p><pre><code>googletag.cmd.push(() =&gt; {
  googletag.pubads().enableSingleRequest();
  googletag.enableServices();
});</code></pre><p>This tells googletag to batch all eligible ad slots into a <strong>single network request</strong>. This is designed specifically for server-rendered pages. The critical constraint here is that all slots you want in the batch must be defined&#8212;and otherwise ready (i.e. header bidding is completed)&#8212;before the first &#8220;googletag.display&#8221; call.</p><p>This is a killer reason to get your slot definitions going pre-hydration. Fewer network requests has performance benefits&#8212;reducing RTT and main thread contention&#8212;but the real benefit is in what Google Ad Manager does with a bundled request: it enables portfolio-level optimization. Advertisers want reach and context, and giving them that context increases their willingness to bid. This also allows Google Ad Manager to evaluate your set of ads as a whole, and unlock bundle-based pricing.</p><h2>Duplicate Definitions</h2><p>One gotcha here is that you must make sure not to define the slot twice&#8212;this can happen if, for example, you use strict mode. I recommend creating an object from which to manage all your ads scripts that is built from a &#8220;once&#8221; function.</p><h2>Client-Side Navigation</h2><p>Once you have your initial page load correct, there&#8217;s just one more thing you need to worry about: client-side navigation.</p><p>While it&#8217;s useful overall for page performance to not reload everything every time a link is clicked, without a page reload your ad scripts won&#8217;t know to load new ads.</p><p>This simply means you have to refresh your ads manually when your navigation route changes, e.g.:</p><pre><code>&#8220;use client&#8221;;
import { useEffect } from &#8220;react&#8221;;
import { usePathname } from &#8220;next/navigation&#8221;;

export default function GamRefresh() {
  const path = usePathname();

  useEffect(() =&gt; {
    if (window.googletag?.pubads) {
      googletag.pubads().refresh();
    }
  }, [path]);

  return null;
}</code></pre><h2>Conclusion</h2><p>When you first attempt to convert to a static site generator, it might look like a daunting regression. With just a few tweaks, however, you can see both your site&#8217;s performance and revenue leap ahead. It&#8217;s worth the investment!</p><p>If you&#8217;d like to explore more about how to optimize your ads, I recommend examining how <a href="https://klovell.substack.com/p/collapsible-ad-slots-hurt-cls">collapsible ad slots can hurt CLS.</a></p>]]></content:encoded></item><item><title><![CDATA[Collapsible Ad Slots Hurt Your Page Performance]]></title><description><![CDATA[Balancing Revenue and User Experience]]></description><link>https://entanglement.games/p/collapsible-ad-slots-hurt-cls</link><guid isPermaLink="false">https://entanglement.games/p/collapsible-ad-slots-hurt-cls</guid><dc:creator><![CDATA[Kathryn Lovell]]></dc:creator><pubDate>Mon, 15 Dec 2025 14:08:27 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/10955fb5-b8ae-4f5d-af1b-82a27a9b0557_640x484.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>It can often be tempting to use collapsible slots in the case that, for whatever reason, an ad doesn&#8217;t fill. While this is perhaps an attempt at elegant error handling, in practice this often leads to a degraded user experience. This can be particularly pronounced when we let static rendering take care of the content before populating ad slots.</p><p>Cumulative Layout Shift (CLS) is one of Google&#8217;s Core Web Vitals. The Core Web Vitals are a base measure user experience on your page, and affect search rankings. CLS in particular measures how much the page &#8220;shifts around&#8221; as it loads.</p><p>An ad slot that is collapsed while it loads, and expands once it does, is then naturally going to have negative effects on your CLS metric.</p><p>So what can you do instead?</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://entanglement.games/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">Thanks for reading Kathryn's Substack! Subscribe for free to receive new posts and support my work.</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><h3>Avoid Disruptive Positioning</h3><p>One method to fix this is to avoid ads embedded in your content&#8212;this is where classic sidebar ads shine. While perhaps a little old fashioned, sidebar ads are tried and true. They typically have high viewability, and thus excellent profitability. They are also minimally disruptive to your user&#8217;s experience; they don&#8217;t get in the way of what your user came here to see.</p><h3>Fetch Ads Before Slots Render At All</h3><p>More fashionably, if you have an infinite scroll feed on your site, the UI for subsequent content is typically loaded in chunks. Ads can be stealthily requested just before a new feed section is likely to be requested. This allows a decision to be made as to whether or not to render the slot based on whether or not the pre-fetched ad request fills.</p><h3>Backfill Ads with Your Own Subscription Upsell</h3><p>If you have ads that are part of your initial page load, and are also positioned to disrupt content&#8212;for example, a large &#8220;billboard&#8221;-style header ad&#8212;the cleanest way to handle cases where an ad fails to catch a bid is to use the unfilled inventory yourself. You likely also sell a subscription&#8212;this is the perfect opportunity to promote it.</p><p></p><p>Ads are often described as a necessary evil. But when done well, they can provide maximum value to both your business and your user, while minimally disrupting your intended experience.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://entanglement.games/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://entanglement.games/subscribe?"><span>Subscribe now</span></a></p><p></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://entanglement.games/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">Thanks for reading Kathryn's Substack! Subscribe for free to receive new posts and support my work.</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>]]></content:encoded></item></channel></rss>