<?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[TagoWill | Root Access Devlog]]></title><description><![CDATA[I’m an Unreal Engine developer with years of experience building immersive VR experiences. Now, I’m turning that expertise toward something personal — designing and developing his own game from the ground up. This is where I documents the journey.]]></description><link>https://tagowill.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!sRm5!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd483c2e6-3b33-4da9-b823-7fa316ada914_811x811.jpeg</url><title>TagoWill | Root Access Devlog</title><link>https://tagowill.substack.com</link></image><generator>Substack</generator><lastBuildDate>Fri, 17 Jul 2026 11:55:38 GMT</lastBuildDate><atom:link href="https://tagowill.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[TagoWill]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[tagowill@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[tagowill@substack.com]]></itunes:email><itunes:name><![CDATA[TagoWill | Root Access Devlog]]></itunes:name></itunes:owner><itunes:author><![CDATA[TagoWill | Root Access Devlog]]></itunes:author><googleplay:owner><![CDATA[tagowill@substack.com]]></googleplay:owner><googleplay:email><![CDATA[tagowill@substack.com]]></googleplay:email><googleplay:author><![CDATA[TagoWill | Root Access Devlog]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Whose Turn Is It Anyway? | Root Access Devlog #10]]></title><description><![CDATA[Sit down with this game for the first time and one thing becomes clear fairly quickly: the two sides don&#8217;t share the same rhythm.]]></description><link>https://tagowill.substack.com/p/whose-turn-is-it-anyway-root-access</link><guid isPermaLink="false">https://tagowill.substack.com/p/whose-turn-is-it-anyway-root-access</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Mon, 15 Jun 2026 05:30:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cbEc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cbEc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cbEc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 424w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 848w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 1272w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cbEc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png" width="1408" height="684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:684,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2438029,&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://tagowill.substack.com/i/201577353?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.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_!cbEc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 424w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 848w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.png 1272w, https://substackcdn.com/image/fetch/$s_!cbEc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1aeeee7a-7390-4a19-b0f4-794b58f8ffd1_1408x684.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>Sit down with this game for the first time and one thing becomes clear fairly quickly: the two sides don&#8217;t share the same rhythm. The Corporation and the Runner have different priorities, different relationships with time, different ways of thinking about what a turn is for. Modelling that in code means understanding what each side does on their turn and why the structure of each turn exists in the first place.</p><div><hr></div><h4>The Basic Shape of a Turn</h4><p>Both players operate on clicks. Each turn, a player receives a fixed number of clicks to spend on actions. The Corp gets three clicks per turn. The Runner gets four. That gap is intentional: the Runner needs the extra tempo to have any hope of keeping pace with a Corporation that is quietly building servers, advancing agendas, and layering ICE across its infrastructure.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><p>A click can be spent on a wide range of things: playing a card, gaining a credit, drawing a card, advancing an agenda, making a run. Each action costs one click unless a card says otherwise. When your clicks are gone, your turn is over.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;f758e1b0-20a7-47bc-9a56-7027956098f3&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// Both sides share the same base click tracking
UPROPERTY(Replicated)
int32 ClicksRemaining;

// But start with different amounts
CorpClicksPerTurn = 3;
RunnerClicksPerTurn = 4;</code></pre></div><h4>The Corp Turn</h4><p>The Corporation&#8217;s turn has a defined structure beyond simply spending clicks. It begins with a mandatory draw: the Corp draws one card before anything else happens. Then the click phase opens and the Corp spends their three clicks however they choose. The turn ends with a hand size check: if the Corp is holding more than five cards, they must discard down to five before passing priority to the Runner.</p><p>That mandatory draw is worth thinking about. The Corp doesn&#8217;t choose whether to draw. It keeps the game moving, ensures the Corp is progressing, and means the Corp&#8217;s hand size is in gentle flux throughout the game. It also carries a quiet cost: if the Corp's deck runs dry and they are forced to draw from an empty pile, the game ends immediately in a Runner victory. That threat sits in the background of every Corp decision. Playing cards too freely empties the deck faster. Holding too many cards means discarding at the end of turn, which accelerates it just as much. Knowing when to play, when to hold, and how many cards are left is part of what makes playing Corp different from playing Runner.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;0fef4684-179d-44fe-908e-6b590c3d01f8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">void UCorpActions::BeginCorpTurn()
{
    // Mandatory draw before clicks open
    DrawCard(CorpPlayer, 1);
    ClicksRemaining = CorpClicksPerTurn;
}

void UCorpActions::EndCorpTurn()
{
    // Discard down to maximum hand size if over
    EnforceHandSizeLimit(CorpPlayer, MaxCorpHandSize);
}</code></pre></div><h4>The Runner Turn</h4><p>The Runner&#8217;s turn has no mandatory draw and no end-of-turn discard. Four clicks, spend them how you like, pass priority back to the Corp when they&#8217;re gone. That freedom is the Runner&#8217;s defining characteristic: pure agency, constrained only by resources and what&#8217;s been installed.</p><p>Where the Corp is managing a slow-building machine, the Runner is deciding when to apply pressure and when to hold back. Every run costs clicks and potentially credits. Every failed run costs tempo. The four clicks are a budget as much as they are actions.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;3743991f-1e14-4fbd-a6e9-3b0a3ba784c8&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">void URunnerActions::BeginRunnerTurn()
{
    // No mandatory draw &#8212; Runner chooses everything
    ClicksRemaining = RunnerClicksPerTurn;
}</code></pre></div><h4>What the Action Manager Actually Does</h4><p>Underneath the turn structure sits the action manager &#8212; the system responsible for knowing, at any given moment, what a player is and is not allowed to do.</p><p>This is more involved than it might sound. A player can only spend clicks on their own turn. Certain actions are only available to one side. Some cards open windows where the other player can respond before an action resolves. The action manager tracks turn ownership, validates every action request against the current game state, and rejects anything outside what the rules permit.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;51be4f1b-2ede-4267-a5f7-b008f9a6bfc9&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">bool UActionManager::IsActionValid(EActionType Action, ANetrunnerPlayerController* PC)
{
    // Wrong turn
    if (!IsActivePlayer(PC)) return false;
    
    // No clicks remaining
    if (ClicksRemaining &lt;= 0) return false;
    
    // Action not permitted in current game state
    if (!IsActionPermittedInCurrentPhase(Action)) return false;

    return true;
}</code></pre></div><p>Nothing reaches the game state unless the action manager approves it. The server validates every request before anything changes. A client can ask to do whatever it likes but the action manager is what decides whether the game agrees.</p><h4>Why the Asymmetry Matters</h4><p>It would have been simpler to give both sides the same turn structure and the same number of clicks. The fact that the game doesn&#8217;t do that is part of what makes this worth building.</p><p>The turn structure communicates what each side is supposed to feel like. The Corp is methodical, accumulating, building towards something. The Runner is reactive, opportunistic, picking the right moment to strike. That difference starts in the click count and the mandatory draw and radiates outward into every decision both players make.</p><p>Getting that into code cleanly is one of the more satisfying things this project has produced so far.</p><div><hr></div><p>Next week I&#8217;ll go deeper into the economy (&#8220;credits&#8221;) of the game, how they&#8217;re earned and spent, and how the game tracks the resource layer that sits underneath every decision both players make.</p><p>See you then.</p><div><hr></div><h4>Supporters</h4><p>If you would like to appear here, you can support the project via the <a href="https://buymeacoffee.com/tagowill">buymeacoffee </a>or by <a href="https://tagowill.substack.com/">subscribing to my substack</a> to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[The Disaster, Resolved | Root Access Devlog #9]]></title><description><![CDATA[Last week I left you with a project that was fundamentally broken and no fix in sight.]]></description><link>https://tagowill.substack.com/p/the-disaster-resolved-root-access</link><guid isPermaLink="false">https://tagowill.substack.com/p/the-disaster-resolved-root-access</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 31 May 2026 05:30:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VR3R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VR3R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VR3R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 424w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 848w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 1272w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VR3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png" width="1407" height="685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/edda0061-c620-4930-9566-0388343e3921_1407x685.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:685,&quot;width&quot;:1407,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2087623,&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://tagowill.substack.com/i/196639746?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.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_!VR3R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 424w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 848w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.png 1272w, https://substackcdn.com/image/fetch/$s_!VR3R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fedda0061-c620-4930-9566-0388343e3921_1407x685.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>Last week I left you with a project that was fundamentally broken and no fix in sight. Client-side ticks not firing, BeginPlay silent, timelines collapsing after a single pulse. Something systemic, something deep, and at that point something I hadn&#8217;t identified yet.</p><p>So let&#8217;s dive into the issue and solve it.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><h4>Getting Methodical</h4><p>The breakthrough came from forcing myself to slow down and stop throwing solutions at the wall. I started completely fresh.</p><p>New project. Install the template. Copy my code across (thankfully I had structured everything as a self-contained module from the beginning, which meant moving it was straightforward rather than surgical). Then I began reparenting the classes one by one, reintroducing my code into the template piece by piece, and running the game after each change.</p><p>The idea was simple: keep playing until it breaks, and whatever I changed last is the culprit.</p><p>It broke. I found it.</p><h4>The Culprit</h4><p>The issue came down to a single class mismatch. CCG Toolkit uses <code>AGameState</code> as the base for its game state class. My code used <code>AGameStateBase</code>.</p><p>To anyone who hasn&#8217;t spent time in Unreal&#8217;s networking internals, those two things sound like they should be interchangeable, one just a more specific version of the other. In practice, the difference is significant.</p><p><code>AGameStateBase</code> is the minimal foundation. It handles the bare essentials of tracking game state and replicating it to clients, but it deliberately leaves out higher-level functionality to keep things lightweight. <code>AGameState</code>, which extends it, adds the machinery that Unreal&#8217;s multiplayer framework actually depends on for a fully connected game: player array management, match state tracking, and critically, the replication hooks that keep clients properly synchronised with the server.</p><p>When you mix the two, a <code>GameMode</code> expecting <code>AGameState</code> behaviour sitting on top of a class that only provides <code>AGameStateBase</code>, the replication system quietly falls apart. Not loudly, not with an obvious crash. It just stops working in specific, baffling ways. Ways that look, from the outside, exactly like client-side ticks not firing, BeginPlay not triggering, and timelines dying after a single frame.</p><p>The entire disaster, traced back to one class hierarchy mismatch.</p><h4>Why It Was So Hard to Find</h4><p>Everything else was working. Spawning an actor on the server and having it appear on the client: working. Calling client RPCs and having them execute correctly: working. Players connecting, exchanging information, replicating data back and forth: working. The replication system was not broken. It was functioning exactly as it should across almost every surface I was testing against.</p><p>That&#8217;s precisely what made this so hard to track down. When most things work, you assume the foundation is solid. You look for the bug in the code you wrote last, not in a class you chose at the very beginning. The failure was surgical, specific enough to be invisible against the backdrop of everything that was functioning correctly, but catastrophic enough to make the thing I actually needed to build completely impossible.</p><p>And as for why my code was using <code>AGameStateBase</code> in the first place? There is no elegant answer to this one. When I created the class, I searched for &#8220;game state&#8221; in Unreal&#8217;s class picker and clicked the first result. That was it. No careful consideration, no cross-referencing with the template, no checking whether I was picking the right variant. I just clicked the first thing that looked right and moved on.</p><p>A two-second decision at the start of the project that cost me the better part of two weeks to diagnose. That&#8217;s the job sometimes.</p><h4>The Part That Hurts</h4><p>Here is the part I have to be honest about.</p><p>The answer was in the log file the entire time.</p><pre><code><code>LogGameMode: Error: Mixing AGameStateBase with AGameMode is not compatible. 
Change AGameStateBase subclass (CardGameState_C) to derive from AGameState, 
or make both derive from Base.</code></code></pre><p>Right there. Explicit. Named the exact class causing the problem. I had walked past that line repeatedly while I was actively dismantling the template, and I had dismissed it as noise, a side effect of the intentional breaking rather than a signal worth following.</p><p>It wasn&#8217;t noise. It was the answer, sitting patiently in the logs waiting for me to read it carefully.</p><p><strong>Read your logs</strong>. All of them. Even the ones that appear while you&#8217;re doing something else.</p><h4>The Honest Version of How This Felt</h4><p>Before I found this, I was close to throwing in the towel. Not on the project entirely, but on the current codebase. I was seriously considering scrapping everything and starting a new project from scratch, accepting the loss and rebuilding with fresh eyes.</p><p>The methodical approach saved me from that. Going back, resetting, reintroducing changes one at a time rather than staring at a broken whole. That process is what made the answer findable. It wasn&#8217;t glamorous. It wasn&#8217;t fast. But it worked, and it saved me an amount of time I don&#8217;t want to calculate.</p><p>Not having tick working on the client is one of those problems that feels impossible precisely because it shouldn&#8217;t be possible. The framework is supposed to handle that. When it doesn&#8217;t, your instinct is to question everything: your code, your architecture, your life choices. The real answer, in this case, was far simpler than any of that.</p><p>Sometimes stepping all the way back is the only way to move forward.</p><div><hr></div><h4>What&#8217;s Next</h4><p>With the project back on stable ground, I can finally get into the gameplay systems properly. Next week I&#8217;ll talk about the action manager and turn structure, how the game decides whose turn it is, what actions are available, and how it enforces the rules when a player tries to do something they shouldn&#8217;t.</p><p>See you then.</p><h4><strong>Supporters</strong></h4><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Marcel Encarna&#231;&#227;o</p></li></ul><p>If you would like to appear here, you can support the project via the <a href="http://buymeacoffee.com/tagowill">buymeacoffee </a>or by subscribing to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[The Big Disaster | Root Access Devlog #8]]></title><description><![CDATA[Some weeks you find out that something you thought was working never really was.]]></description><link>https://tagowill.substack.com/p/the-big-disaster-root-access-devlog</link><guid isPermaLink="false">https://tagowill.substack.com/p/the-big-disaster-root-access-devlog</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 24 May 2026 05:31:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!j5YN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!j5YN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!j5YN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 424w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 848w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 1272w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!j5YN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png" width="1407" height="678" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:678,&quot;width&quot;:1407,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2158268,&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://tagowill.substack.com/i/196639698?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.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_!j5YN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 424w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 848w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.png 1272w, https://substackcdn.com/image/fetch/$s_!j5YN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8819dae5-3df0-4ee1-9bd3-f6db10dc92b1_1407x678.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>Some weeks you find out that something you thought was working never really was. My first major bug that nearly drove me to madness.</p><div><hr></div><p>It started simply enough. I was wiring up the 3D card movement, the moment a card physically travels from one place to another on the board. Visually, one of the more satisfying things to get right. I had the card spawning correctly, data flowing from the server to the client, commands being received and acknowledged. Everything pointed to this being straightforward.</p><p>Then I tried to move the card and nothing happened.</p><p>There was no errors on the logs, no crashes&#8230; just nothing. The card sat exactly where it was, completely indifferent to the fact that it was supposed to be moving.</p><p>I started digging. The movement logic lived on the tick (the function that runs in every frame). So I did the simplest possible test: I dropped a print string into the tick on the client side. Just a line of text that would appear on screen every frame to confirm the tick was running.</p><p><strong>Nothing printed on the log.</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><p>That was strange. The card was spawning correctly on the client, the server was generating it and the client was receiving it. RPC calls were going through. Data was replicating. But the tick? Silent.</p><p>I took a step back and checked <code>BeginPlay</code> (the function that fires once when an actor first enters the world). If anything was going to work on the client, it should be that.</p><p>Also silent.</p><p>At this point I was no longer looking at a card movement bug. I was looking at something deeper and considerably more unsettling.</p><div><hr></div><h4>Ruling Things Out</h4><p>I went through everything methodically. Replication settings =&gt; checked and rechecked. Forced tick enabled explicitly in the constructor. Verified the actor was set to replicate. Tried variations, combinations, approaches I&#8217;d already tried once because I was running out of ideas.</p><p>Nothing changed. The client side remained completely unresponsive. Tick not firing. BeginPlay not firing. And yet any RPCs calls where working with data replicating, spawning correct. The contradiction made no sense.</p><p>Then I thought I&#8217;d found a way around it. If tick wasn&#8217;t firing reliably on the client, maybe I could drive the card movement through a timeline instead (a defined animation curve that plays out over time rather than recalculating every frame). Cleaner, arguably more appropriate for smooth card movement anyway. I wired it up and ran it.</p><p>The timeline fired once. Then stopped completely. No loop, no continuation, just a single pulse and then silence&#8230; as if something was actively preventing anything time-based from sustaining itself on the client. Tick broken. BeginPlay broken. Timelines broken. It wasn&#8217;t one unlucky system. It was everything that depended on time passing on the client side.</p><p>So I ran a final test. I created a completely fresh actor. No logic, no systems, nothing inherited from the project. Just a simple replicated actor with a single print string on tick that said &#8220;<em>hello world&#8221;</em>. I dragged it into the map, which is always replicated to connected clients, and pressed play.</p><p>Just the server printed the logs. The client printed nothing.</p><p>I was losing my mind a little by this point.</p><div><hr></div><h4>The Moment It Clicked</h4><p>One more test. I opened a completely fresh Unreal project. Clean template, nothing carried over from my work. Created the exact same actor. Dragged it into the map. Connected a client.</p><p>It worked immediately. Tick firing. BeginPlay firing. &#8220;Hello world&#8221; printing on both ends exactly as it should.</p><p>The template worked. My project didn&#8217;t. We are now getting somewhere.</p><p>After more testing, the conclusion was unavoidable: something in my project is broken at a fundamental level. Client-side ticks and BeginPlay events are not firing at all. Not just for cards, not just for replicated actors, but across the board. A silent, systemic failure that had been sitting underneath everything, invisible until I tried to do something that depended on it.</p><div><hr></div><h4>Where Things Stand</h4><p>I know what the problem is. I know where it lives. I&#8217;ve already found the solution, but I&#8217;ll save it for the next post. If you&#8217;re an Unreal Engine developer, I&#8217;d love for you to leave a comment guessing what the issue might be. It&#8217;s easier than you think! Based on my description, I&#8217;m curious to see if you can spot exactly what&#8217;s going on.</p><div><hr></div><h4>Supporters</h4><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Andre Fonseca</p></li></ul><p>If you would like to appear here, you can support the project via the <a href="http://buymeacoffee.com/tagowill">buymeacoffee </a>or by subscribing to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[From Nothing to Something | Root Access Devlog #7]]></title><description><![CDATA[I want to do share the current progress of the project this week.]]></description><link>https://tagowill.substack.com/p/from-nothing-to-something-root-access</link><guid isPermaLink="false">https://tagowill.substack.com/p/from-nothing-to-something-root-access</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 17 May 2026 05:31:17 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!F6fr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I want to do share the current progress of the project this week.</p><p>There are moments where I can check on my progress, where something that didn&#8217;t exist a few weeks ago is suddenly there and working. And then I look at how far there still is to go, and the two feelings sit next to each other in a way that is hard to describe. Proud, but grounded.</p><p>That feels about right for where this project is.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><h4>Stage 1: The Codebase</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F6fr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F6fr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 424w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 848w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 1272w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F6fr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png" width="1456" height="926" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/db5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:926,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1760869,&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://tagowill.substack.com/i/196633268?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.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_!F6fr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 424w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 848w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 1272w, https://substackcdn.com/image/fetch/$s_!F6fr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdb5f4f6e-f4ec-4362-bbf9-6c4d8e6eec44_1880x1196.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It started with nothing visible at all. Just code. Data structures, card definitions, game state logic. The invisible foundation that everything else would eventually sit on top of. There was no board, no cards on screen, no interface of any kind. Just a server that knew what a card was, what a player was, and how the two related to each other.</p><p>This is the stage that is hardest to show and easiest to underestimate. Nothing looked like a game. But without this, nothing that came after would have been possible.</p><h4>Stage 2: Pseudo Cards</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gBtj!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gBtj!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 424w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 848w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 1272w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gBtj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png" width="1456" height="899" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:899,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:3017252,&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://tagowill.substack.com/i/196633268?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.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_!gBtj!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 424w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 848w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 1272w, https://substackcdn.com/image/fetch/$s_!gBtj!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b28413f-7097-4db6-85c0-4a6658e5bedd_2288x1413.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Before real card data existed, I needed something to test against. I created a list of pseudo cards, just placeholders definitions that had the right shape without being the real thing. Enough structure to run logic against, enough variety to expose edge cases (hopefully, however, It never catches everything).</p><p>It&#8217;s unglamorous work. But it&#8217;s the kind of unglamorous work that saves you from discovering fundamental problems much later, when they are far more expensive to fix.</p><h4>Stage 3: 2D Cards</h4><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;4d980e33-6c77-4666-a5e0-9b4a4f8084de&quot;,&quot;duration&quot;:null}"></div><p>This was the first moment it started to feel like something.</p><p>Cards appearing on screen. A hand that held them. A player that could look at what they&#8217;d drawn. The information flowing from the server &#8594; card names, costs, types &#8594; down to the client and into a 2D widget that displayed it correctly.</p><p>Seeing a card on screen for the first time, knowing that the data behind it came from the server and was filtered correctly before it arrived, was a quietly significant moment.</p><h4>Stage 4: 3D Cards</h4><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;da94a6b2-6aad-41eb-83b1-b0e543c5c7eb&quot;,&quot;duration&quot;:null}"></div><p>The next step was the transition from hand to board. When a card is played, it stops being a flat 2D widget and becomes a 3D actor in the world, a physical presence on the table rather than a UI element in your hand.</p><p>Getting this right meant the card information had to travel cleanly from the server, through the 2D representation in hand, and into the 3D actor when it hit the board. The data pipeline had to hold together across that entire journey without losing anything or misrepresenting anything.</p><h4>Stage 5: Board Layout</h4><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!J6g-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!J6g-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 424w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 848w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 1272w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!J6g-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png" width="1456" height="873" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:873,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:7083899,&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://tagowill.substack.com/i/196633268?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.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_!J6g-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 424w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 848w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.png 1272w, https://substackcdn.com/image/fetch/$s_!J6g-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5aeebff-f2a1-4e0e-8f17-6c6e34eef57d_3056x1833.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 board is taking shape. Zones for servers, the runner&#8217;s rig (still missing), the central areas where both players interact. The physical aspect of the game is becoming visible for the first time.</p><p>It is still early. There is no gameplay loop running end to end yet. But the table exists. The space where the game will happen is starting to look like the space where the game will happen.</p><h3>Where This Leaves Us</h3><p>Six weeks of work. A codebase, a card pipeline, a network layer, a board that is beginning to resemble something real.</p><p>There is a lot still to build: the full run system, ICE encounters, economy, win conditions, proper card art, sound, UI polish. The list is long and I am one person.</p><p>But the list felt longer when I was staring at a blank project and talking myself out of starting. At least now there is something to look at.</p><p>Next week I&#8217;ll get back into the systems: the action manager, turn structure, and how the game decides what you are and aren&#8217;t allowed to do on any given turn.</p><p>See you then.</p><div><hr></div><h4>Supporters</h4><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Jared Meritt</p></li><li><p>Marcel Encarnacao</p></li><li><p><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Jay Rooney&quot;,&quot;id&quot;:57310144,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9cef105-37dd-4377-82e5-70f012caadc6_400x400.jpeg&quot;,&quot;uuid&quot;:&quot;d2238042-382d-438f-9669-416808fcf63d&quot;}" data-component-name="MentionToDOM"></span> </p></li></ul><p>If you would like to appear here, you can support the project via the <a href="http://buymeacoffee.com/tagowill">buymeacoffee </a>or by subscribing to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[The Moment Two Players Become a Game | Root Access Devlog #6]]></title><description><![CDATA[This week I built the network layer. How two players connect, submit their decks, and signal they're ready. The moment both confirmations land, the server starts the game.]]></description><link>https://tagowill.substack.com/p/the-moment-two-players-become-a-game</link><guid isPermaLink="false">https://tagowill.substack.com/p/the-moment-two-players-become-a-game</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 10 May 2026 05:30:37 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!3ZLi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3ZLi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3ZLi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 424w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 848w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 1272w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3ZLi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png" width="1407" height="562" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:562,&quot;width&quot;:1407,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1612060,&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://tagowill.substack.com/i/196164108?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.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_!3ZLi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 424w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 848w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.png 1272w, https://substackcdn.com/image/fetch/$s_!3ZLi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a53e113-769b-4f84-9a8a-95c32223091f_1407x562.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>There is a specific kind of satisfaction that comes from watching something work for the first time.</p><p>Not the satisfaction of a feature being finished, or a bug being fixed. Something quieter than that. The moment where a system you&#8217;ve been building in pieces, wiring together in your head long before it existed in code, finally does the thing it was always supposed to do. Both ends talking to each other. The handshake completing. The game beginning.</p><p>That moment happened this week. And it felt good.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><h2>The Problem to Solve</h2><p>Before a single card can be played, before the first run is declared or the first credit is spent, two people need to find each other across a network, agree that they are both ready, submit their decks, and hand control over to the game. It sounds like very foreword . It is anything but.</p><p>This is the part of a multiplayer game that players never think about because, when it works, it&#8217;s invisible. You click a button, you&#8217;re in a game. What actually happened in between is a surprisingly involved sequence of events, and getting that sequence right, in the right order, with the right checks at each step, is the kind of work that quietly determines whether everything built on top of it is stable or fragile.</p><h2>How Players Connect</h2><p>When a player joins the server, Unreal&#8217;s networking layer fires a <code>PostLogin</code> event. This is the entry point: the moment the server becomes aware that someone new has arrived. From here, the network manager registers the incoming player controller, assigns them a role, and begins tracking their state.</p><p>Two players need to connect before anything else can happen. The server waits. It doesn&#8217;t assume. It doesn&#8217;t proceed until both seats are filled and both players have been properly registered. That patience is intentional, rushing past it is how you end up with race conditions that only appear in production, when two real people connect at slightly different times and the game state ends up in a place it was never supposed to be.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;18235301-f7f8-42c5-9a1b-f41ab7512324&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// Called by the server when a player successfully connects
void ANetrunnerGameState::RegisterPlayerController(ANetrunnerPlayerController* PC)
{
    ConnectedPlayers.Add(PC);
    if (ConnectedPlayers.Num() == 2)
    {
        OnBroadcastBothPlayersConnected();
    }
}</code></pre></div><h2>Submitting a Deck</h2><p>Once both players are connected, each one submits their deck to the server. This is not a client-side operation. The deck data travels to the server, the server validates it (checking that it&#8217;s legal, that it&#8217;s complete, that it belongs to the right side) and stores it. The client doesn&#8217;t get to decide what&#8217;s in its own deck. The server does.</p><p>This matters more than it might seem. A client that could manipulate its own deck after submission is a client that could cheat in ways that are very difficult to detect. By pushing validation entirely to the server, that attack surface disappears before it ever opens.</p><h2>The Ready-Up Flow</h2><p>With decks submitted, each player signals that they are ready. The server waits for both confirmations (<strong>not one, both</strong>) before proceeding. When the second ready signal arrives, the server calls <code>StartGame()</code>, initialises the full game state, and fires a <code>Client_GameReady</code> RPC to each player.</p><p>That RPC is the signal. On the client side, it means: the game is real now. Draw your opening hand. The board is live.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;9a23340e-bb64-45c3-95b5-670ae7d1c99c&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">void ANetrunnerGameState::Server_ReadyUp(ANetrunnerPlayerController* PC)
{
    ReadyPlayers.Add(PC);
    if (ReadyPlayers.Num() == 2)
    {
        StartGame();
    }
}</code></pre></div><p>The full sequence - <code>PostLogin</code> &#8594; <code>RegisterPlayerController</code> &#8594; <code>Server_SubmitDeck</code> &#8594; <code>Server_ReadyUp</code> &#8594; <code>BothPlayersReady</code> &#8594; <code>StartGame()</code> &#8594; <code>Client_GameReady</code> - is wired end to end. Every step hands off cleanly to the next. Nothing proceeds until it&#8217;s supposed to.</p><h2>Why That Moment Mattered</h2><p>When I ran it for the first time and watched the log trace the full sequence without errors: both players registering, both decks submitting, both ready signals arriving, the game starting&#8230; I sat back for a second and just looked at it.</p><p>It&#8217;s not a card game yet. There are no cards on the table, no runs, no ICE to break through. But two players can now connect to a server, tell it they are ready, and receive confirmation that a game has begun. The skeleton is standing up. Everything built from here has somewhere to stand.</p><p>That felt like something worth noting.</p><div><hr></div><p>Next week I&#8217;ll start getting into the gameplay systems themselves. The action manager, how turns are structured, and how the game decides whose move it is and what they&#8217;re allowed to do.</p><p>See you then.</p><div><hr></div><h4>Supporters</h4><p>If you would like to appear here, you can support the project via the <a href="https://buymeacoffee.com/tagowill">buymeacoffee </a>or by <a href="https://tagowill.substack.com/">subscribing to my substack</a> to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[Standing on Shoulders, or Building Your Own? | Root Access Devlog #5]]></title><description><![CDATA[This week I unpacked the decision that stopped me from starting this project sooner: template or scratch?]]></description><link>https://tagowill.substack.com/p/standing-on-shoulders-or-building</link><guid isPermaLink="false">https://tagowill.substack.com/p/standing-on-shoulders-or-building</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 03 May 2026 05:30:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kliw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kliw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kliw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 424w, https://substackcdn.com/image/fetch/$s_!kliw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 848w, https://substackcdn.com/image/fetch/$s_!kliw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 1272w, https://substackcdn.com/image/fetch/$s_!kliw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kliw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png" width="1408" height="677" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:677,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1968566,&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://tagowill.substack.com/i/195391507?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.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_!kliw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 424w, https://substackcdn.com/image/fetch/$s_!kliw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 848w, https://substackcdn.com/image/fetch/$s_!kliw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.png 1272w, https://substackcdn.com/image/fetch/$s_!kliw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b33803e-699b-44df-a629-cfb61e0b6145_1408x677.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>I spent longer than I should have on this one.</p><p>If I&#8217;m being completely honest, this decision is part of why this project didn&#8217;t start sooner. It had been sitting in the back of my mind for a long time. The game I wanted to build, the engine I wanted to use, the rough shape of what it could be. But every time I got close to actually starting, this question was there waiting for me. Template or scratch. Shoulders or foundation. And instead of deciding, I&#8217;d just... not. The paralysis of it was quieter than I expected. It didn&#8217;t feel like fear. It just felt like not quite being ready. Not quite having the answer. And so the project stayed an idea for longer than it needed to.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><p>Eventually I made a call. This is how I got there.</p><h2>The Template in Question</h2><p>There is a tool on the Unreal Marketplace called CCG Toolkit. It&#8217;s a multiplayer card game framework. A fully built foundation that gives you a working card game skeleton out of the box. Animations, menus, card previews, hand and deck management. The kind of scaffolding that takes weeks to build properly if you&#8217;re starting from nothing.</p><p>It&#8217;s well regarded. It&#8217;s actively maintained. And when I first found it, I was genuinely tempted.</p><h2>The Case For It</h2><p>The visual side of a card game is deceptively time-consuming. Getting cards to lift cleanly off a deck, arc into a hand, and land on a board in a way that feels satisfying is not a trivial animation problem. CCG Toolkit has that done. The 2D-to-3D transition (<em>the moment a card moves from your hand into play and becomes a presence on the board</em>) is already there. Card preview on hover, simple menus, basic UI chrome. All of it, already done.</p><p>For a solo developer with no dedicated artist and no unlimited runway, that is not a small thing. That is weeks of work handed to you on day one.</p><h2>The Case Against It</h2><p>CCG Toolkit is not just a collection of useful components. It is an entire card game system with its own opinions about how a card game should work. Learning to use it properly means learning how it thinks: its assumptions, its data flow, its architecture. That investment of time doesn&#8217;t disappear just because the end result looks faster.</p><p>And this game is not a simple card game. The rules are dense. The state machine is complex. The asymmetry between the two sides means almost nothing in a standard card game framework maps cleanly onto what I need. Every new rule, every new game state, every interaction I wire in is going to push against the edges of a system that was never designed with this specific game in mind. At some point&#8230;<em> and I don&#8217;t think it&#8217;s a distant point&#8230;</em> things will start to break in ways that are difficult to trace because the foundation wasn&#8217;t built for this.</p><p>There&#8217;s also a longer-term cost that&#8217;s easy to underestimate. Everything in CCG Toolkit that I don&#8217;t use is still there, sitting in the project, adding noise. Eventually there will be a <strong>reckoning</strong>. A cleanup pass where I strip out everything that doesn&#8217;t belong. That work doesn&#8217;t go away. It just gets deferred.</p><p>And perhaps the most uncomfortable truth: the time it takes to properly learn how CCG Toolkit works is probably not far off the time it would take to build the pieces I actually need from scratch. At a certain point, understanding a system deeply enough to bend it to your will and understanding how to build it yourself are nearly the same thing.</p><h2>The Decision</h2><p><code>I&#8217;m using it.</code></p><p>The reason is simple, and it took me longer than it should have to see it clearly: I am not trying to build a finished game right now. I am trying to build a vertical slice: a focused, playable demonstration of what this game can feel like. Something I can put in front of people and ask whether it&#8217;s worth continuing. Something that proves the concept before I commit to the full architecture.</p><p>For that goal, the visual polish CCG Toolkit brings on day one is genuinely valuable. If the vertical slice lands, if there&#8217;s traction and appetite for the game, then the deeper architectural work (<em>the cleanup, the rebuild, the from-scratch systems</em>) is a problem worth having. It means the project survived long enough to need solving.</p><p>If I spend six months building everything perfectly from scratch and nobody wants to play it, I&#8217;ve built something perfect that nobody wants.</p><p>The template gets me to the demo faster. The demo tells me whether any of this is worth it. That&#8217;s the logic. I&#8217;m committing to it.</p><div><hr></div><p>Next week I&#8217;ll get into the network manager. How players actually connect, how the ready-up flow works, and what happens in the gap between two people joining a lobby and the first card hitting the table.</p><p>See you then.</p><div><hr></div><h4>Supporters</h4><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project or subscribed to my substack. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Andre Lizardo</p></li><li><p><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Onur&quot;,&quot;id&quot;:319275477,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98aac153-ba37-4c8c-ae2f-4a6d1afcc378_1170x1149.jpeg&quot;,&quot;uuid&quot;:&quot;a4362cb5-82cc-4181-993d-fcf9ed38b9ca&quot;}" data-component-name="MentionToDOM"></span> </p></li><li><p><span class="mention-wrap" data-attrs="{&quot;name&quot;:&quot;Alex Antra&quot;,&quot;id&quot;:212251032,&quot;type&quot;:&quot;user&quot;,&quot;url&quot;:null,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c39272d4-d76e-4aa9-8eeb-2314a4037937_2048x2048.png&quot;,&quot;uuid&quot;:&quot;7b4ea617-a494-4868-b811-09846387cb2c&quot;}" data-component-name="MentionToDOM"></span></p></li><li><p>Irina Ferreira</p></li><li><p>Andre Fonseca</p></li></ul><p>If you would like to appear here, you can support the project via the <a href="http://buymeacoffee.com/tagowill">buymeacoffee </a>or by subscribing to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading! 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><item><title><![CDATA[Who Owns the Truth? | Root Access Devlog #4]]></title><description><![CDATA[How a card game benefits from server authority.]]></description><link>https://tagowill.substack.com/p/who-owns-the-truth-root-access-devlog</link><guid isPermaLink="false">https://tagowill.substack.com/p/who-owns-the-truth-root-access-devlog</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 26 Apr 2026 05:30:56 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!jxgB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!jxgB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!jxgB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 424w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 848w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 1272w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!jxgB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png" width="1408" height="684" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:684,&quot;width&quot;:1408,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2438029,&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://tagowill.substack.com/i/195210894?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.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_!jxgB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 424w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 848w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.png 1272w, https://substackcdn.com/image/fetch/$s_!jxgB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff9c69097-2aab-4c33-b470-0d50da251f8f_1408x684.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>Last week I talked about separating card data from card visuals. This week I want to go one level higher and talk about something that shaped the entire network architecture from day one, before a single line of multiplayer code was written.</p><p>The question was simple: <strong>when two players disagree about the state of the game, who is right?</strong></p><p>The answer, it turns out, determines almost everything.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><h2>The Decision</h2><p>Some multiplayer games trust the clients. Each player&#8217;s machine tracks its own version of the game state, and the server acts as a middleman. It passes messages back and forth, reconcile differences when they arise. It&#8217;s a reasonable approach for certain types of games. Fast-paced games where a few milliseconds of latency matter more than perfect accuracy can benefit from letting clients run ahead and correcting later.</p><p>A card game is not that.</p><p>In a card game (especially one as rules-dense as this) the state of the game at any given moment is sacred. Who has how many credits. Which cards are installed. Whether that ICE is <em>rezzed</em> or not. Whether a run is currently active and at which stage. These are not things you want two different machines to have two different answers to.</p><p>So I made a deliberate choice early: the server owns all truth. Always. Without exception.</p><p>The clients (your machine, your opponent&#8217;s machine) are displays. They show you what the server tells them is real. When you take an action, you don&#8217;t update your own game state. You send a request to the server, the server validates it, the server updates the state, and the server tells both clients what has changed. Your screen updates because the server said so, not because your machine decided it should.</p><h2>Why It Matters for This Game Specifically</h2><p>Most multiplayer games benefit from server authority. This one depends on it in a way that goes deeper than cheat prevention.</p><p>Netrunner is built on hidden information. The Corp&#8217;s hand is never visible to the Runner. Unrezzed ICE has a presence on the board but its identity is secret until the Corp chooses to reveal it. Agendas sit in remote servers, indistinguishable from assets or traps, until someone accesses them.</p><p>In a client-trusted model, enforcing this cleanly is genuinely difficult. If a client knows too much about the game state, even information it isn&#8217;t supposed to display, that information can be extracted. A determined player with the right tools could see the Corp&#8217;s hand before making a run. That isn&#8217;t a edge case. That&#8217;s a fundamental break in the game.</p><p>With a server-authoritative model, the problem largely disappears. The Runner&#8217;s client never receives information about the Corp&#8217;s hidden cards in the first place. The server filters what each client is allowed to know before it sends anything. There is nothing to extract because the data was never there.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;d6e652a0-90b0-4fa0-bac2-e01dc79981b1&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// The server sends only what each client is allowed to see
// Corp hand and unrezzed cards are never replicated to the Runner client
void ANetrunnerGameState::FilterStateForClient(APlayerController* PC)
{
    if (IsRunnerController(PC))
    {
        // Strip hidden Corp information before sending
    }
}</code></pre></div><p>It's a cleaner model. And for a game where secrets are mechanically central, it's the only model that makes sense.</p><h2>The Trade-off</h2><p>Server authority means every action has a round trip. You click something, the server processes it, the server responds, your screen updates. In a fast-paced action game that latency would be noticeable and painful. In a turn-based card game where actions are deliberate and measured, it&#8217;s essentially invisible.</p><p>That trade-off is, honestly, one of the reasons a game like this is well suited to this architecture in a way that other genres aren&#8217;t. That doesn&#8217;t always happen. When it does, you take it.</p><div><hr></div><p>Next week I&#8217;ll get into the network manager itself: how players connect, how the ready-up flow works, and what actually happens under the hood between the moment two players join a game and the moment the first card is drawn.</p><p>See you then.</p><div><hr></div><h4>Supporters</h4><p>If you would like to appear here, you can support the project via the <a href="https://buymeacoffee.com/tagowill">buymeacoffee </a>or by <a href="https://tagowill.substack.com/">subscribing to my substack</a> to get extra content and preview of the posts.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"></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><item><title><![CDATA[The Architecture of a Card | Root Access Devlog #3]]></title><description><![CDATA[Designing and coding the card instance and why it is important]]></description><link>https://tagowill.substack.com/p/week-3-the-architecture-of-a-card</link><guid isPermaLink="false">https://tagowill.substack.com/p/week-3-the-architecture-of-a-card</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 19 Apr 2026 08:01:06 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!cLZF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!cLZF!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!cLZF!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!cLZF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg" width="725" height="483.4993131868132" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:725,&quot;bytes&quot;:3585832,&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://tagowill.substack.com/i/194241908?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.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_!cLZF!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!cLZF!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faba0bfa1-e0c0-4989-b78e-fcac7f88cfa0_6000x4000.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>This week I want to talk about something that took me longer to get right than I&#8217;d like to admit.</p><p>It doesn&#8217;t sound glamorous. It&#8217;s not a feature you&#8217;ll ever see in a trailer or a screenshot. But it&#8217;s the kind of decision that quietly determines whether a codebase stays manageable or slowly becomes something you dread opening. And hitting the wall that led me here was, in a strange way, one of the more clarifying moments of the project so far.</p><h2>The Problem</h2><p>Early on, I made what felt like a perfectly reasonable assumption: a card is a card. It exists in the world, it has state (strength, counters, whether it&#8217;s rezzed or not) and it needs to be visible on the screen. So I built it as one thing. An actor. A physical object in the game world that held all of its own data and rendered itself.</p><p>This works fine. Right up until it doesn&#8217;t.</p><p>The moment I started thinking seriously about multiplayer layer, about a server that needs to track the true state of every card in the game, hidden information that should never reach the wrong client, cards that exist in a hand or a deck but aren&#8217;t visible yet, the single-object approach started showing its cracks. The server doesn&#8217;t need to render anything. It just needs to know the state of the game. Forcing it to deal with visual actors to do that felt wrong in a way I couldn&#8217;t ignore.</p><p>Then came the hidden information problem. In Netrunner, the Corp&#8217;s hand and unrezzed cards are never visible to the Runner. If every card is an actor that manages its own state and its own presentation, enforcing that cleanly becomes surprisingly difficult. You end up fighting the architecture instead of building on top of it.</p><p>So I stopped, stepped back, and split the concept in two.</p><h2>The Solution: Two Things, Not One</h2><p>The insight was simple once I let myself see it: a card&#8217;s data and a card&#8217;s appearance are not the same thing, and they don&#8217;t need to live in the same place.</p><p><code>UCardInstance</code> is now the true representation of a card in the game. It&#8217;s a lightweight object with no visuals and no presence in the world. That holds everything the game logic needs to know. Strength, counters, rez state, which server it&#8217;s installed on, its unique identifier. The server creates these, owns them, and uses them to run the game. They exist whether or not anyone is looking at them.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;14fd19d2-1523-404e-9907-67e7a25077e2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// UCardInstance holds all runtime state
int32 CurrentStrength;
bool bIsRezzed;
int32 HostileCounters;
FGuid CardGUID;</code></pre></div><p><code>ACardBase</code>, by contrast, is now just a shell. A thin visual actor that gets spawned into the world only when a card actually needs to be seen. It reads from a <code>UCardInstance</code> to know what to display, but it holds no game state of its own. When a card is in a deck or a hand that shouldn&#8217;t be visible, there&#8217;s no actor for it at all.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;cpp&quot;,&quot;nodeId&quot;:&quot;6b4c0db6-c2fa-4138-aac3-5af6c9e567d2&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-cpp">// ACardBase is just the visual &#8212; it references a UCardInstance
UPROPERTY()
UCardInstance* CardData;</code></pre></div><p>It&#8217;s a clean line. Data lives in one place. Presentation lives in another. The server works entirely with <code>UCardInstance</code> objects and never has to think about rendering. The client spawns <code>ACardBase</code> actors only for the cards it&#8217;s actually allowed to see.</p><h3>Why It Matters</h3><p>This is not the kind of decision that feels satisfying in the moment you make it. There&#8217;s no new feature to show. Nothing looks different. You&#8217;ve spent a day&#8230; <strong>or several&#8230;</strong> restructuring something that was already working, just working badly in ways that hadn&#8217;t fully surfaced yet.</p><p>But the alternative is building a skyscraper on a foundation that has a quiet crack running through it. You might not notice it for months. And then one day the building shifts, and you understand exactly why that crack mattered.</p><p>Getting the architecture right before the complexity compounds is, I think, most of what separates projects that finish from projects that don&#8217;t. I&#8217;m trying to stay on the right side of that line.</p><p>That&#8217;s the deep end for this week. Next week I&#8217;ll pull back out and talk about the network layer: how you build a server-authoritative multiplayer system for a game where hidden information isn&#8217;t just a feature, it&#8217;s fundamental to how the game works.</p><p>See you then.</p><div><hr></div><p>Supporters</p><p>If you would like to appear here, you can support the project via the <a href="https://buymeacoffee.com/tagowill">buymeacoffee </a>or by <a href="https://tagowill.substack.com/">subscribing to my substack</a> to get extra content and preview of the posts.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://tagowill.substack.com/subscribe?"><span>Subscribe now</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[The Game Has a Name | Root Access Devlog #2]]></title><description><![CDATA[Last week I talked about the engine. This week I owe you the thing I've been dancing around since week zero.]]></description><link>https://tagowill.substack.com/p/week-2-the-game-has-a-name-creating</link><guid isPermaLink="false">https://tagowill.substack.com/p/week-2-the-game-has-a-name-creating</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sun, 12 Apr 2026 10:23:23 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!hiIi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!hiIi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!hiIi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!hiIi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg" width="1456" height="838" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:838,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2140458,&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://tagowill.substack.com/i/193948689?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.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_!hiIi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 424w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 848w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!hiIi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb297242f-707f-4d92-9c06-cec9b4cecb02_4032x2321.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">My own collection</figcaption></figure></div><p>The game is <strong>Netrunner</strong>, or rather, it&#8217;s my take on it. A digital game deeply inspired by it, built around the same ideas, the same asymmetry, the same philosophy. I don&#8217;t hold the licensing rights to the Netrunner name or its cards, and I want to be upfront about that. What I&#8217;m building is a love letter, not a replica. Whether it ends up a faithful adaptation or something that grows into its own thing, I honestly don&#8217;t know yet. But Netrunner is where it starts.</p><h2>A Friend Who Knew Me Too Well</h2><p>I didn&#8217;t find Netrunner. It was handed to me.</p><p>A good friend sat me down one day with a very specific kind of confidence &#8212; the confidence of someone who has already done the calculation and knows exactly how this is going to go. <em>&#8220;This,&#8221;</em> he said, <em>&#8220;is the exact type of game you&#8217;re going to fall in love with.&#8221;</em></p><p>He was right. Annoyingly, completely right.</p><p>I don&#8217;t think I fully understood what I was looking at the first time. Two players. Completely different decks. Completely different rules for each side. One plays a corporation hiding agendas behind layers of ICE, intrusion countermeasures, the digital walls that stand between a hacker and the secrets they&#8217;re after. The other plays the Runner, a hacker trying to crack through all of it with nothing but wit, credits, and whatever programs they&#8217;ve managed to install before the run begins.</p><p>It sounds complicated because it is. But it&#8217;s complicated in the way a good novel is complicated. Every layer you pull back reveals something more interesting underneath.</p><h3>Not Another Card Game</h3><p>I want to be clear about something, because I think it matters for understanding why this project exists.</p><p>Netrunner is not Hearthstone. It is not Legends of the Runeterra. It is not a game about building the biggest number or drawing the best card. <strong>And crucially, it is not a game that hides behind RNG</strong>.</p><p>RNG is the thing that quietly kills my interest in most card games. That feeling of losing not because your opponent outplayed you, but because they drew the right card at the right moment. Or winning and knowing, deep down, that luck did most of the work. After enough hours with a game like that, it stops feeling like a game and starts feeling like a slot machine with extra steps. It gets boring. It gets frustrating. It stops being worth my time.</p><p>Netrunner doesn&#8217;t do that. Every card you draw, you drew because you built your deck to draw it. Every run succeeds or fails because of decisions (<strong>yours and your opponent&#8217;s</strong>). There is no topdeck that saves you. There is no lucky pull that wins the game. What you bring to the table is what you have, and what you do with it is entirely up to you.</p><p>That is not a small thing. In a genre full of games that use randomness as a crutch, Netrunner treats its players like adults.</p><p>There is also no &#8220;meta&#8221; in the traditional sense where one deck simply beats all others. Every game is a conversation, a psychological back and forth where bluffing, timing, and reading your opponent matter as much as the cards in your hand.</p><p>The asymmetry is the point. The Corporation and the Runner don&#8217;t just have different cards. They have different win conditions, different tempos, different ways of thinking about the board. Playing one side teaches you almost nothing about playing the other. It is, genuinely, two games happening simultaneously at the same table.</p><p>That kind of design doesn&#8217;t exist anywhere else. Not like this (at least to my knowledge).</p><h3>A Game That Refuses to Die</h3><p>Netrunner has had a complicated life. It passed through the hands of companies who eventually decided it wasn&#8217;t worth their time. It was discontinued. Most games don&#8217;t survive that.</p><p><strong>This one did</strong>, because its community wouldn&#8217;t let it go. <a href="https://nullsignal.games/">Null Signal Games</a>, a fan organisation, picked up the torch and has been developing and publishing new cards ever since. Entirely volunteer-run. Entirely out of love for something they believed deserved to keep existing.</p><p>That&#8217;s the part that got me. A game so good that when the industry moved on, the people who loved it simply decided to keep making it themselves. There&#8217;s something in that story that feels worth honouring. And it&#8217;s part of why I feel comfortable building something in this space. This is a community that understands what it means to make something out of passion rather than profit.</p><p>Whether what I build ends up being a direct adaptation or something that finds its own identity along the way, the heart of it will always be rooted here.</p><p>Next week I get into the architecture: what it actually looks like to try and model something this rules-dense in code, and the early decisions that are either going to save me or come back to haunt me.</p><p>If you&#8217;ve played Netrunner before and you&#8217;re reading this, I&#8217;d genuinely love to hear from you. And if this is your first time hearing about it, go find a friend who plays.</p><p>Subscribe to keep being updated. See you next week.</p><div><hr></div><h3>Supporters</h3><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Andreia Antunes</p></li></ul><p>If you would like to appear here, you can support the project via the buymeacoffee or by paid subscriptions to get extra content and preview of the posts. </p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"></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><item><title><![CDATA[Why Unreal? | Root Access Devlog #1]]></title><description><![CDATA[Last week I planted a flag.]]></description><link>https://tagowill.substack.com/p/week-1-why-unreal</link><guid isPermaLink="false">https://tagowill.substack.com/p/week-1-why-unreal</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sat, 11 Apr 2026 18:45:07 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!VTAH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VTAH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VTAH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 424w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 848w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 1272w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VTAH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif" width="1200" height="675" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:675,&quot;width&quot;:1200,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:179157,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/avif&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://tagowill.substack.com/i/193909120?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VTAH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 424w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 848w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 1272w, https://substackcdn.com/image/fetch/$s_!VTAH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F79e1950a-1738-4b2b-b104-e59ddc7c2e3b_1200x675.avif 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">Image by: UnrealEngine website</figcaption></figure></div><p>Last week I planted a flag. This week I have to start giving some content.</p><blockquote><p><em>A quick note before I get into it: this blog is, at its core, a personal log. I&#8217;m documenting my experience, my ideas, and my journey as honestly as I can. I want to be upfront, this is an ambitious project for a solo developer, and there&#8217;s a <strong>high chance it hits a wall I can&#8217;t climb over</strong>. I&#8217;m not promising a finished game. I&#8217;m promising to show up every week and tell you exactly where things stand.</em></p></blockquote><p>Let me start with the question I&#8217;ve already been asking myself: why on earth am I building a card game in Unreal Engine 5?</p><p>It&#8217;s a fair challenge. Card games live happily in Unity. Some of the best digital card games ever made were built in frameworks far lighter than UE5. There&#8217;s an argument (a reasonable one, I think) that reaching for Unreal to build something that is, at its core, about rectangles with text on them is like hiring an architect to build a bookshelf.</p><p>I heard that argument. I disagree with it.</p><h2><strong>The Alternatives</strong></h2><p>I did consider the obvious candidates.</p><p><strong>Unity</strong> was the first thing I looked at. It&#8217;s the natural home for this kind of project. Unity have a huge community, mountains of tutorials, proven track record with card games specifically. But Unity and I have history, and not all of it&#8217;s good. The last couple of years haven&#8217;t exactly made me trust the direction it&#8217;s heading: a licensing model that left a lot of developers feeling burned, decisions that seemed designed for shareholders rather than the people actually building things, and a market that appears to quietly agree. For a solo passion project, I need to trust the foundation I&#8217;m building on. Right now, I don&#8217;t.</p><p><strong>Godot</strong> genuinely tempted me. Lightweight, open source, a community that feels like it&#8217;s building something with real conviction. For a different project, at a different time, I think I&#8217;d be there. But it would mean starting from zero with an unfamiliar toolset, and I don&#8217;t have unlimited runway right now.</p><p>In the end, the choice was simpler than I made it sound.</p><h2><strong>The Real Reason</strong></h2><p>I know Unreal. Not perfectly but well enough that I can move fast when I need to, and debug confidently when things go wrong. Starting a solo project during an already uncertain period isn&#8217;t the time to also be learning the fundamentals of a new engine. I needed at least one fewer unknown variable.</p><p>There&#8217;s also Blueprint. Being able to move fluidly between C++ for the systems that need it and Blueprint for the logic that doesn&#8217;t is exactly the kind of flexibility a solo developer needs. I can write the architecture in code and wire up card behaviours visually without context switching into a completely different mental mode. That matters more than I expected it to.</p><p>But honestly? There&#8217;s a third reason, and it&#8217;s the one that feels hardest to justify on paper.</p><p>This game, <em>the one I&#8217;m adapting</em>, deserves to feel like more than a card game. It has atmosphere. It has a world. The aesthetic is dense and specific and alive. I don&#8217;t want it to feel like a UI exercise. I want it to feel like somewhere you actually go. Unreal gives me the tools to chase that, even if I&#8217;m the only one building it.</p><p>Whether I can actually pull that off is a different question. That&#8217;s what this blog is for.</p><p>Next week I&#8217;ll finally stop being mysterious about which game I&#8217;m actually building. I&#8217;ve been hinting at it long enough and it&#8217;s time to give it a name, tell you why it matters to me, and explain why I think it deserves better than what exists right now.</p><p>As always, if this is interesting to you, share it with someone who&#8217;d get it. And if you want to support the project while it&#8217;s still just a blog and a folder of C++ files, just subscribe to get extra content. Every coffee buys me another hour of not panicking.</p><p>See you next week.</p><h2><strong>Supporters</strong></h2><p>I would like to extend my sincere gratitude to the following individuals who have chosen to support this project. Your contribution means a great deal and helps keep this work moving forward.</p><ul><li><p>Azahar Machwe</p></li><li><p>Sara</p></li><li><p>Elisabete</p></li><li><p>Isabel</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Starting Something | Root Access Devlog #0]]></title><description><![CDATA[I wasn&#8217;t planning to start a dev blog this month.]]></description><link>https://tagowill.substack.com/p/week-0-starting-something</link><guid isPermaLink="false">https://tagowill.substack.com/p/week-0-starting-something</guid><dc:creator><![CDATA[TagoWill | Root Access Devlog]]></dc:creator><pubDate>Sat, 11 Apr 2026 18:36:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!V1JH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!V1JH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!V1JH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 424w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 848w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 1272w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!V1JH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp" width="1100" height="445" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:445,&quot;width&quot;:1100,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:17710,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://tagowill.substack.com/i/193908463?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!V1JH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 424w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 848w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 1272w, https://substackcdn.com/image/fetch/$s_!V1JH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f42a9da-7cf8-4c6e-83fe-8da70b7fd9f7_1100x445.webp 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">Image by Garry Killian from Freepik</figcaption></figure></div><p>I wasn&#8217;t planning to start a dev blog this month. Honestly, I wasn&#8217;t planning most of what this month turned out to be.</p><p>Life has a way of reshuffling your priorities whether you ask it to or not. Mine got reshuffled recently. And somewhere in the quiet that followed, I decided to use the time well.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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><p>I&#8217;ve been turning an idea over in my head for a while now. There&#8217;s a card game I&#8217;ve loved for years &#8212; asymmetric, deep, with a cyberpunk aesthetic that never really let go of me. One side plays a mega-corporation hiding agendas behind layers of ice. The other plays a hacker trying to crack through it all. It&#8217;s one of those games where every decision feels like it matters, and the design is so elegant it almost makes you angry.</p><p>Nobody has done it justice digitally. So I&#8217;m going to try.</p><p>This is going to be a weekly log of that attempt &#8212; the architecture decisions, the dead ends, the moments where it clicks. I&#8217;ll get properly into the weeds next week.</p><p>For now, this post is really just me planting a flag. Saying out loud that I&#8217;m doing this, so that I actually do it. That&#8217;s what week zero is for.</p><p>If any of this sounds interesting to you, I&#8217;d love to hear from you. Would you watch a stream of this being built in real time? If there&#8217;s enough interest, that might be the next step. And if you want to support what I&#8217;m making before it even has a name, you can subscribe and get extra content and preview post. It genuinely helps, and it tells me someone out there is paying attention.</p><p>See you next week.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tagowill.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">This Substack is reader-supported. To receive new posts and support my work, consider becoming a free or paid subscriber.</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>