<?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"><channel><title><![CDATA[stonedtroll]]></title><description><![CDATA[stonedtroll]]></description><link>https://hashnode.stonedtroll.com</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Apr 2026 03:11:02 GMT</lastBuildDate><atom:link href="https://hashnode.stonedtroll.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why a Facing Arc?]]></title><description><![CDATA[When a token turns, it’s helpful—especially in tactical or role-playing scenarios—to see exactly which direction it’s “looking.” A subtle 20º arc projected in front of the token can communicate much more clearly than a bare rotation value.

But how d...]]></description><link>https://hashnode.stonedtroll.com/why-a-facing-arc</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/why-a-facing-arc</guid><category><![CDATA[DDD]]></category><category><![CDATA[TypeScript]]></category><category><![CDATA[foundry-vtt]]></category><category><![CDATA[pixijs]]></category><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Wed, 11 Jun 2025 03:51:06 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749609797536/812b00f3-5d02-4070-9c59-e6b5d8633b80.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When a token turns, it’s helpful—especially in tactical or role-playing scenarios—to see exactly which direction it’s “looking.” A subtle 20º arc projected in front of the token can communicate much more clearly than a bare rotation value.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1749615175062/ec814bde-61e1-4eb8-84ac-30705cef41b0.png" alt class="image--center mx-auto" /></p>
<p>But how do I hook into Foundry’s event system, check permissions, and still keep my code clean and loosely coupled?</p>
<h2 id="heading-foundryhookadapter-infrastructure-layer">FoundryHookAdapter (Infrastructure Layer)</h2>
<p>Detects raw Foundry events and converts them to domain events. By hiding Foundry specifics here, the rest of the app remains blissfully ignorant of Foundry’s peculiarities.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Bear in mind that when Foundry fires the <code>updateToken</code> hook, the Token’s <code>document</code> hasn’t yet been fully updated. If you read <code>document.rotation</code> at that moment, you may still get the <em>old</em> value. Always rely first on the <code>changedState.rotation</code> from the hook payload—and only fall back to <code>document.rotation</code> as a default if no change was provided.</div>
</div>

<pre><code class="lang-typescript"><span class="hljs-comment">// When a token is updated in Foundry:</span>
handleTokenUpdate() {
  <span class="hljs-comment">// Captures the update from Foundry's updateToken hook</span>
  <span class="hljs-comment">// Creates a TokenUpdateEvent with rotation data</span>
  eventBus.emit(<span class="hljs-string">'token:update'</span>, {
    tokenId: <span class="hljs-built_in">document</span>.id,
    currentState: { rotation: <span class="hljs-number">45</span>, x: <span class="hljs-number">100</span>, y: <span class="hljs-number">100</span>, ... },
    changedState: { rotation: <span class="hljs-number">90</span> },  <span class="hljs-comment">// New rotation</span>
    userId: <span class="hljs-string">'abc123'</span>
  });
}
</code></pre>
<h2 id="heading-tokenrotationcoordinator-application-layer">TokenRotationCoordinator (Application Layer)</h2>
<p>Listens for token updates and coordinates overlay rendering when rotation changes.</p>
<ol>
<li><p><strong>Detect rotation change</strong></p>
</li>
<li><p><strong>Fetch overlay types</strong> that respond to token rotation</p>
</li>
<li><p><strong>Check who’s allowed</strong> to see them</p>
</li>
<li><p><strong>Build a render context</strong> (dimensions, angles, positions)</p>
</li>
<li><p><strong>Fire off render requests</strong></p>
</li>
</ol>
<pre><code class="lang-typescript"><span class="hljs-comment">// Subscribed to 'token:update' events</span>
handleTokenUpdate(event: TokenUpdateEvent) {
  <span class="hljs-comment">// Check if rotation changed</span>
  <span class="hljs-keyword">if</span> (event.changedState.rotation !== <span class="hljs-literal">undefined</span>) {
    <span class="hljs-comment">// Get overlays that respond to rotation (like facing-arc)</span>
    <span class="hljs-keyword">const</span> rotationOverlays = overlayRegistry.getTypesForEvent(<span class="hljs-string">'tokenRotate'</span>);

    <span class="hljs-comment">// Check permissions - can this user see overlays on this token?</span>
    <span class="hljs-keyword">const</span> viewableOverlays = <span class="hljs-keyword">await</span> permissionCoordinator.getViewableOverlaysForToken();

    <span class="hljs-comment">// Build render context with rotation data</span>
    <span class="hljs-keyword">const</span> context: OverlayRenderContext = {
      rotation: {
        currentRotation: <span class="hljs-number">45</span>,
        newRotation: <span class="hljs-number">90</span>,
        tokenXCoordinate: <span class="hljs-number">100</span>,
        tokenYCoordinate: <span class="hljs-number">100</span>,
        tokenWidth: <span class="hljs-number">50</span>,
        tokenHeight: <span class="hljs-number">50</span>
      }
    };
</code></pre>
<h2 id="heading-overlayrenderingservice-presentation-layer">OverlayRenderingService (Presentation Layer)</h2>
<p>Manages the PixiJS graphics containers and coordinates rendering.</p>
<ul>
<li><p>Retrieves the overlay definition (<code>FacingArcDefinition</code>)</p>
</li>
<li><p>Instantiates—or reuses—a <code>PIXI.Graphics</code> object</p>
</li>
<li><p>Positions it at the token’s centre</p>
</li>
<li><p>Hands off drawing to the renderer</p>
</li>
</ul>
<pre><code class="lang-typescript">renderTokenOverlay(overlayTypeId: <span class="hljs-string">'facing-arc'</span>, tokenId: <span class="hljs-built_in">string</span>, context: OverlayRenderContext) {
  <span class="hljs-comment">// Get the overlay definition from registry</span>
  <span class="hljs-keyword">const</span> overlayDef = overlayRegistry.get(<span class="hljs-string">'facing-arc'</span>); <span class="hljs-comment">// Returns FacingArcDefinition</span>

  <span class="hljs-comment">// Get the renderer from the definition</span>
  <span class="hljs-keyword">const</span> renderer = overlayDef.getRenderer(); <span class="hljs-comment">// Returns FacingArcRenderer instance</span>

  <span class="hljs-comment">// Get or create PIXI graphics object for this token+overlay</span>
  <span class="hljs-keyword">const</span> graphics = getOrCreateGraphicsInstance(<span class="hljs-string">`<span class="hljs-subst">${tokenId}</span>-facing-arc`</span>);

  <span class="hljs-comment">// Position graphics at token centre</span>
  <span class="hljs-keyword">const</span> centerX = context.rotation.tokenXCoordinate + context.rotation.tokenWidth / <span class="hljs-number">2</span>;
  <span class="hljs-keyword">const</span> centerY = context.rotation.tokenYCoordinate + context.rotation.tokenHeight / <span class="hljs-number">2</span>;
  graphics.position.set(centerX, centerY);

  <span class="hljs-comment">// Delegate actual drawing to the renderer</span>
  renderer.render(graphics, context);
}
</code></pre>
<h2 id="heading-facingarcdefinition-infrastructure-layer">FacingArcDefinition (Infrastructure Layer)</h2>
<p>Defines the facing arc overlay configuration.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> FacingArcDefinition: OverlayDefinition = {
  id: <span class="hljs-string">'facing-arc'</span>,
  renderTriggers: [<span class="hljs-string">'tokenRotate'</span>, <span class="hljs-string">'tokenMove'</span>],
};
</code></pre>
<p>Because it lives in a registry, adding new overlays later (boundary, aura, custom shapes…) is just a matter of dropping in another definition.</p>
<h2 id="heading-facingarcrenderer-presentation-layer">FacingArcRenderer (Presentation Layer)</h2>
<p>Actually draws the facing arc using PixiJS.</p>
<pre><code class="lang-typescript">render(graphics: PIXI.Graphics, context: OverlayRenderContext) {
  <span class="hljs-comment">// Clear previous drawing</span>
  graphics.clear();

  <span class="hljs-comment">// Get rotation from context</span>
  <span class="hljs-keyword">const</span> rotation = context.rotation?.currentRotation ?? <span class="hljs-number">0</span>;
  <span class="hljs-keyword">const</span> radius = <span class="hljs-built_in">Math</span>.max(context.rotation.tokenWidth, context.rotation.tokenHeight) / <span class="hljs-number">2</span>;

  <span class="hljs-comment">// Calculate arc angles (20 degree arc)</span>
  <span class="hljs-keyword">const</span> arcAngle = <span class="hljs-number">20</span> * <span class="hljs-built_in">Math</span>.PI / <span class="hljs-number">180</span>;
  <span class="hljs-keyword">const</span> facingAngle = ((rotation - <span class="hljs-number">90</span>) * (<span class="hljs-built_in">Math</span>.PI / <span class="hljs-number">180</span>));
  <span class="hljs-keyword">const</span> startAngle = facingAngle - arcAngle / <span class="hljs-number">2</span>;
  <span class="hljs-keyword">const</span> endAngle = facingAngle + arcAngle / <span class="hljs-number">2</span>;

  <span class="hljs-comment">// Draw the arc line</span>
  graphics.lineStyle({
    width: <span class="hljs-number">8</span>,
    color: <span class="hljs-number">0x8A6A1C</span>,
    alpha: <span class="hljs-number">0.8</span>,
    cap: PIXI.LINE_CAP.ROUND
  });

  graphics.arc(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, radius, startAngle, endAngle, <span class="hljs-literal">false</span>);
}
</code></pre>
<h2 id="heading-complete-flow-sequence">Complete Flow Sequence</h2>
<ol>
<li><p><strong>User</strong> rotates token in Foundry UI</p>
</li>
<li><p><strong>Foundry</strong> fires <code>updateToken</code> hook</p>
</li>
<li><p><strong>FoundryHookAdapter</strong> catches hook, emits <code>'token:update'</code> event</p>
</li>
<li><p><strong>TokenRotationCoordinator</strong> receives event, checks if rotation changed</p>
</li>
<li><p><strong>Coordinator</strong> queries <code>OverlayRegistry</code> for overlays with <code>'tokenRotate'</code> trigger</p>
</li>
<li><p><strong>Coordinator</strong> checks permissions via <code>OverlayPermissionCoordinator</code></p>
</li>
<li><p><strong>Coordinator</strong> builds render context with rotation data</p>
</li>
<li><p><strong>Coordinator</strong> calls <code>overlayRenderingService.renderTokenOverlay()</code></p>
</li>
<li><p><strong>OverlayRenderingService</strong> gets <code>FacingArcDefinition</code> from registry</p>
</li>
<li><p><strong>Service</strong> calls <code>definition.getRenderer()</code> to get <code>FacingArcRenderer</code></p>
</li>
<li><p><strong>Service</strong> creates/positions PIXI <code>Graphics</code> object</p>
</li>
<li><p><strong>Service</strong> calls <code>renderer.render(graphics, context)</code></p>
</li>
<li><p><strong>FacingArcRenderer</strong> draws the arc at the new rotation angle</p>
</li>
<li><p><strong>Facing arc</strong> appears on screen at token’s new rotation</p>
</li>
</ol>
<h2 id="heading-key-design-patterns">Key Design Patterns</h2>
<ul>
<li><p><strong>Event-Driven</strong>: Loose coupling via an EventBus</p>
</li>
<li><p><strong>Clean Architecture</strong>: Clear separation between infrastructure, application, and presentation layers</p>
</li>
<li><p><strong>Strategy Pattern</strong>: Different renderers implement a common interface for each overlay type</p>
</li>
<li><p><strong>Registry Pattern</strong>: Dynamic registration and lookup of overlay definitions</p>
</li>
<li><p><strong>Permission System</strong>: Fine-grained control over who can see each overlay</p>
</li>
</ul>
<p>This modular architecture makes it trivial to extend—simply drop in a new overlay definition and renderer, and the core flow remains untouched. Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[Coordinating Overlay Permissions]]></title><description><![CDATA[In my project, I’ve got overlays—things like movement paths, elevation indicators, and token’s boundary—that need to appear only when the viewer has permission to see them. To manage this, I’ve built a system called the OverlayPermissionCoordinator.
...]]></description><link>https://hashnode.stonedtroll.com/coordinating-overlay-permissions</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/coordinating-overlay-permissions</guid><category><![CDATA[foundry-vtt]]></category><category><![CDATA[DDD]]></category><category><![CDATA[TypeScript]]></category><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Fri, 06 Jun 2025 10:00:14 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749155967526/f3d5096a-0f6d-4610-ba1c-76694bf3b396.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In my project, I’ve got overlays—things like movement paths, elevation indicators, and token’s boundary—that need to appear <em>only</em> when the viewer has permission to see them. To manage this, I’ve built a system called the <code>OverlayPermissionCoordinator</code>.</p>
<p>It bridges <strong>Foundry VTT’s infrastructure</strong> with my <strong>domain logic</strong>, keeping permissions clean, isolated, and easy to reason about.</p>
<p>Here’s a breakdown of how the whole thing works.</p>
<h2 id="heading-entry-points-where-the-flow-begins">Entry Points: Where the Flow Begins</h2>
<p>Overlay view permission checks kick off in a few key methods:</p>
<pre><code class="lang-plaintext">graph TD
    A[UI/Rendering System] --&gt; B{Which Method?}
    B --&gt; C[canViewOverlayOnToken - Single Check]
    B --&gt; D[canViewOverlaysOnToken - Batch Check]
    B --&gt; E[getViewableOverlaysForToken - Get All Viewable]
</code></pre>
<h2 id="heading-single-overlay-check-canviewoverlayontoken">Single Overlay Check: <code>canViewOverlayOnToken</code></h2>
<p>This is the core function that checks <strong>one overlay</strong> on <strong>one token</strong>. Here's what it does under the hood:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Check if a single overlay is viewable by the user</span>
canViewOverlayOnToken(
    overlayId: <span class="hljs-built_in">string</span>,
    targetToken: Token,
    userId: <span class="hljs-built_in">string</span>,
    isGM: <span class="hljs-built_in">boolean</span>,
    viewerTokens: Token[] = []
): <span class="hljs-built_in">boolean</span> {
    <span class="hljs-keyword">const</span> config = <span class="hljs-built_in">this</span>.registry.get(overlayId);

    <span class="hljs-keyword">if</span> (!config) {
        <span class="hljs-built_in">this</span>.logger.warn(<span class="hljs-string">`Overlay "<span class="hljs-subst">${overlayId}</span>" isn’t registered.`</span>);
        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
    }

    <span class="hljs-comment">// Quick exit if the overlay doesn't require permission checks</span>
    <span class="hljs-keyword">if</span> (!config.usePermissionSystem) {
        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
    }

    <span class="hljs-comment">// Gather the necessary data for a proper check</span>
    <span class="hljs-keyword">const</span> targetData = <span class="hljs-built_in">this</span>.getCachedTokenData(targetToken);
    <span class="hljs-keyword">const</span> viewerData = <span class="hljs-built_in">this</span>.getCachedTokensData(viewerTokens);
    <span class="hljs-keyword">const</span> allVisibleTokens = <span class="hljs-built_in">this</span>.getAllVisibleTokensData();

    <span class="hljs-comment">// Let the domain service handle the actual decision</span>
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.permissionService.canViewOverlaysOnToken(
        targetData,
        userId,
        isGM,
        viewerData,
        allVisibleTokens
    );
}
</code></pre>
<h3 id="heading-step-by-step">Step-by-step:</h3>
<ol>
<li><p><strong>Registry Lookup</strong></p>
<ul>
<li><p>Pulls the overlay config from the registry</p>
</li>
<li><p>If not found, returns <code>false</code></p>
</li>
</ul>
</li>
<li><p><strong>Fast Path Check</strong></p>
<ul>
<li><p>If <code>usePermissionSystem === false</code>, returns <code>true</code> immediately</p>
</li>
<li><p>This skips heavy logic for overlays that don’t need it</p>
</li>
</ul>
</li>
<li><p><strong>Data Conversion (Cached)</strong></p>
<ul>
<li><p>Converts <code>targetToken</code> and <code>viewerTokens[]</code> into <code>TokenSightData</code></p>
</li>
<li><p>Fetches all visible tokens if needed</p>
</li>
</ul>
</li>
<li><p><strong>Domain Permission Check</strong></p>
<ul>
<li><p>Calls <code>permissionService.canViewOverlays()</code></p>
</li>
<li><p>This service lives in the pure domain layer—no Foundry types involved</p>
</li>
</ul>
</li>
<li><p><strong>Return Result</strong></p>
<ul>
<li>Comes back with a <code>boolean</code> based on the domain logic</li>
</ul>
</li>
</ol>
<h2 id="heading-caching-strategy-keep-it-fast-keep-it-simple">Caching Strategy: Keep It Fast, Keep It Simple</h2>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">I've got a sneaking feeling this is just a case of good old-fashioned gold plating — but we’ve chosen the path, so let’s follow it and see if there’s a leprechaun at the end.</div>
</div>

<p>To avoid re-converting tokens constantly, I’ve built a lightweight caching layer:</p>
<pre><code class="lang-typescript"><span class="hljs-comment">// Token Data Cache Flow</span>
    ┌─────────────────┐
    │  Foundry Token  │
    └────────┬────────┘
             ↓
┌────────────────────────┐
│   Generate Cache Key   │ → <span class="hljs-string">`<span class="hljs-subst">${token.id}</span>-<span class="hljs-subst">${cacheGeneration}</span>`</span>
└────────────┬───────────┘
             ↓
        ┌────┴────┐
        │ Cached? │
        └────┬────┘
             ↓
         No ─┴── Yes
         ↓        ↓
      Convert    Return
      &amp; Store    Cached
</code></pre>
<p>The key includes a generation number so I can invalidate it whenever needed (e.g. when tokens move or vision updates).</p>
<h2 id="heading-example-flow-full-walkthrough">Example Flow: Full Walkthrough</h2>
<p>Let’s say a user hovers over a token. I want to know which overlays are visible to them:</p>
<pre><code class="lang-typescript">getViewableOverlaysForToken(token, userId, isGM, viewerTokens)
</code></pre>
<h3 id="heading-behind-the-scenes">Behind the scenes:</h3>
<ol>
<li><p>Grab all overlays from the registry:<br /> <code>['movement-path', 'elevation-indicator', 'status-effects']</code></p>
</li>
<li><p>Call the batch check:<br /> <code>canViewOverlaysOnToken([...], token, userId, isGM, viewerTokens)</code></p>
</li>
<li><p>For each overlay:</p>
<ul>
<li><p><code>movement-path</code>: needs permission → check domain</p>
</li>
<li><p><code>elevation-indicator</code>: doesn’t need permission → allow</p>
</li>
<li><p><code>status-effects</code>: needs permission → check domain</p>
</li>
</ul>
</li>
<li><p>Result:<br /> <code>['elevation-indicator', 'status-effects']</code><br /> (assuming <code>movement-path</code> was denied)</p>
</li>
</ol>
<h2 id="heading-why-this-works-for-me">Why This Works for Me</h2>
<p>This setup gives me:</p>
<ul>
<li><p><strong>Separation of concerns</strong><br />  Foundry stays out of my domain logic. My domain doesn’t even <em>know</em> Foundry exists.</p>
</li>
<li><p><strong>Performance</strong><br />  The system avoids unnecessary work and reuses data wherever possible.</p>
</li>
<li><p><strong>Flexibility</strong><br />  I can add new permission types or overlay rules without touching Foundry code.</p>
</li>
<li><p><strong>Testability</strong><br />  Domain services are testable in isolation, no mocks needed.</p>
</li>
<li><p><strong>Maintainability</strong><br />  All Foundry-specific stuff lives in one place—the coordinator.</p>
</li>
</ul>
<p>If you’re wrangling overlays in a similar way or building on Foundry and trying to decouple things, I think this structure makes it much easier to reason about and test.</p>
]]></content:encoded></item><item><title><![CDATA[Overlay Visibility & Domain Design: How I Keep It Clean and Playable]]></title><description><![CDATA[When I think about overlays in a tabletop-style virtual environment—like range rings, blocked-status indicators, and vision cones—visibility becomes crucial. I want to make sure what players see on the screen reflects what their characters could logi...]]></description><link>https://hashnode.stonedtroll.com/overlay-visibility-and-domain-design-how-i-keep-it-clean-and-playable</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/overlay-visibility-and-domain-design-how-i-keep-it-clean-and-playable</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[DDD]]></category><category><![CDATA[foundry-vtt]]></category><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Thu, 05 Jun 2025 12:42:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749127025641/301d24a7-0425-46a2-9b46-3c3a082609ed.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I think about overlays in a tabletop-style virtual environment—like range rings, blocked-status indicators, and vision cones—visibility becomes crucial. I want to make sure what players see on the screen reflects what their characters could logically perceive in the game world.</p>
<h2 id="heading-overlay-visibility-requirements">Overlay Visibility – Requirements</h2>
<h3 id="heading-for-players">For Players</h3>
<p>As a player, I only want overlays to show up <strong>when they make sense</strong>—meaning, I should only see an overlay if my character would be able to see the token it’s attached to. This helps preserve immersion and makes decision-making more intuitive.</p>
<p>If I have a token selected, I want its overlays to show—of course. But for overlays on <em>other</em> tokens, I only want to see them if:</p>
<ul>
<li><p>The other token is visible on the canvas</p>
</li>
<li><p>It’s not hidden in the scene configuration</p>
</li>
<li><p>It lies within the selected token’s vision polygon</p>
</li>
<li><p>There are no walls or barriers blocking line of sight</p>
</li>
</ul>
<p>When no token is selected, I want the system to fall back on visibility from <em>all</em> tokens I control—so overlays still show accurately based on what my characters could see collectively.</p>
<h3 id="heading-for-gms">For GMs</h3>
<p>As a GM, it’s a different story. I want to see <strong>everything</strong>—all overlays, all the time. Full visibility means I can keep an eye on the battlefield, check for inconsistencies, and help players when needed.</p>
<h2 id="heading-domain-layer-my-approach">Domain Layer – My Approach</h2>
<p>Now, to support this behaviour in code, I’ve been thinking carefully about how to model the domain. Here’s how I’ve structured things.</p>
<p>I use <strong>four main layers</strong> in my domain model:</p>
<ol>
<li><p><strong>Entities</strong> – Mutable objects with identity</p>
</li>
<li><p><strong>Value Objects</strong> – Immutable domain concepts</p>
</li>
<li><p><strong>Interfaces</strong> – Contracts for infrastructure and external services</p>
</li>
<li><p><strong>Types</strong> – Lightweight, structural definitions (like enums, DTOs, configs)</p>
</li>
</ol>
<h3 id="heading-entities-things-that-change-and-persist">Entities – Things That Change and Persist</h3>
<p>Entities are objects that have a <strong>unique ID</strong> and <strong>mutable state</strong>. For example:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> MoveableToken {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">readonly</span> id: <span class="hljs-built_in">string</span>,
        <span class="hljs-keyword">private</span> position: Vector2,
        <span class="hljs-keyword">private</span> rotation: <span class="hljs-built_in">number</span>,
        <span class="hljs-keyword">private</span> collisionShape: CollisionShape
    </span>) {}

    move(newPosition: Vector2): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.position = newPosition;
    }

    rotate(newRotation: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.rotation = newRotation;
    }
}
</code></pre>
<p>What makes this an entity:</p>
<ul>
<li><p>It has identity (<code>id</code>)</p>
</li>
<li><p>Its state can change (<code>position</code>, <code>rotation</code>)</p>
</li>
<li><p>I consider two entities the same if they share the same ID—not necessarily the same data</p>
</li>
</ul>
<h3 id="heading-value-objects-immutable-by-design">Value Objects – Immutable by Design</h3>
<p>Value objects are all about immutability and equality by value:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> Vector2 {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params">
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">readonly</span> x: <span class="hljs-built_in">number</span>,
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">readonly</span> y: <span class="hljs-built_in">number</span>
    </span>) {}

    add(other: Vector2): Vector2 {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> Vector2(<span class="hljs-built_in">this</span>.x + other.x, <span class="hljs-built_in">this</span>.y + other.y);
    }

    equals(other: Vector2): <span class="hljs-built_in">boolean</span> {
        <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.x === other.x &amp;&amp; <span class="hljs-built_in">this</span>.y === other.y;
    }
}
</code></pre>
<p>I reach for value objects when I want:</p>
<ul>
<li><p>Domain expressiveness</p>
</li>
<li><p>Predictability</p>
</li>
<li><p>Thread safety</p>
</li>
<li><p>Easy equality comparison</p>
</li>
</ul>
<h3 id="heading-interfaces-contracts-for-flexibility">Interfaces – Contracts for Flexibility</h3>
<p>Interfaces help me define <strong>what</strong> needs to be done, not <strong>how</strong>.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> LineOfSightChecker {
    isBlocked(origin: Vector2, destination: Vector2): <span class="hljs-built_in">boolean</span>;
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> TokenOwnershipProvider {
    getOwnedTokenIds(userId: <span class="hljs-built_in">string</span>): <span class="hljs-built_in">string</span>[];
}
</code></pre>
<p>This makes it easy for me to swap implementations, mock them during tests, or inject platform-specific logic without tying it to my domain.</p>
<h3 id="heading-types-pure-data">Types – Pure Data</h3>
<p>I use types and enums to represent pure data without behaviour:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> GridType {
    Gridless = <span class="hljs-number">0</span>,
    Square = <span class="hljs-number">1</span>,
    Hex = <span class="hljs-number">2</span>
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">interface</span> SceneConfig {
    gridType: GridType;
    gridSize: <span class="hljs-built_in">number</span>;
    useElevation: <span class="hljs-built_in">boolean</span>;
    sceneCeiling: <span class="hljs-built_in">number</span>;
    enable3DPathfinding: <span class="hljs-built_in">boolean</span>;
    maxStepHeight: <span class="hljs-built_in">number</span>;
}
</code></pre>
<p>Types are lightweight and ideal for:</p>
<ul>
<li><p>Configs</p>
</li>
<li><p>DTOs</p>
</li>
<li><p>Enums and constraints</p>
</li>
<li><p>Representing shape without logic</p>
</li>
</ul>
<h3 id="heading-choosing-the-right-tool-for-the-job">Choosing the Right Tool for the Job</h3>
<p>Purpose</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td></td><td>Entity</td><td>Value Object</td><td>Interface</td><td>Type</td></tr>
</thead>
<tbody>
<tr>
<td>What it represents</td><td>A thing with identity</td><td>A concept with value</td><td>A contract for a service</td><td>A data structure</td></tr>
<tr>
<td>Has identity?</td><td>O</td><td>X</td><td>X</td><td>X</td></tr>
<tr>
<td>Mutable?</td><td>O</td><td>X</td><td>X</td><td>X</td></tr>
<tr>
<td>Behaviour?</td><td>Rich methods</td><td>Domain-specific</td><td>Method signatures only</td><td>None</td></tr>
<tr>
<td>Example</td><td><code>MoveableToken</code></td><td><code>Vector2</code>, <code>Distance</code></td><td><code>LineOfSightChecker</code></td><td><code>SceneConfig</code>, <code>GridType</code></td></tr>
</tbody>
</table>
</div><h3 id="heading-why-this-structure-works-for-me">Why This Structure Works for Me</h3>
<p>This approach keeps my codebase:</p>
<ul>
<li><p><strong>Testable</strong> – Logic lives in pure functions and classes</p>
</li>
<li><p><strong>Modular</strong> – Interfaces separate infrastructure from domain</p>
</li>
<li><p><strong>Extensible</strong> – Easy to extend or replace parts of the system</p>
</li>
<li><p><strong>Readable</strong> – Clear boundaries make it easier to reason about</p>
</li>
</ul>
<p>By thinking in terms of <strong>entities</strong>, <strong>value objects</strong>, <strong>interfaces</strong>, and <strong>types</strong>, I avoid the dreaded "everything is just a class" pitfall. It also helps me align gameplay logic (like overlay visibility) with clean architectural decisions.</p>
<p>I think this is a strong foundation for building features that are both fun to use and maintainable to develop. If you’ve got similar patterns—or different ones—I’d love to hear about them.</p>
]]></content:encoded></item><item><title><![CDATA[Building My Second Foundry VTT Module: Maleficar Manoeuvres]]></title><description><![CDATA[After finishing my first Foundry VTT module, I felt like I had a much better grasp of how Foundry works under the hood—and a clearer sense of what I wish I'd done differently the first time. So, I’ve started working on a second project: Maleficar Man...]]></description><link>https://hashnode.stonedtroll.com/building-my-second-foundry-vtt-module-maleficar-manoeuvres</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/building-my-second-foundry-vtt-module-maleficar-manoeuvres</guid><category><![CDATA[foundry-vtt]]></category><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Thu, 05 Jun 2025 03:16:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1749092838058/9bc524f5-b5f5-4f5b-8788-a7697586d5b0.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>After finishing my first Foundry VTT module, I felt like I had a much better grasp of how Foundry works under the hood—and a clearer sense of what I <em>wish</em> I'd done differently the first time. So, I’ve started working on a second project: <em>Maleficar Manoeuvres</em>, a module aimed at improving token movement and tactical gameplay in Foundry VTT v13.</p>
<p>This time around, I’m trying to push a little further, experiment a bit more, and apply some structure to how I approach things.</p>
<h2 id="heading-the-goal-assisted-movement"><strong>The Goal: Assisted Movement</strong></h2>
<p><em>Maleficar Manoeuvres</em> is about making movement during combat smoother and more helpful for players and GMs. The idea is to provide:</p>
<ul>
<li><p><strong>Pathfinding</strong> to show efficient routes,</p>
</li>
<li><p><strong>Collision detection</strong> so players can’t accidentally (or intentionally) walk through walls and other tokens,</p>
</li>
<li><p><strong>Visual aids</strong> like boundaries, facing, movement ranges, and potential hazards.</p>
</li>
</ul>
<p>I want the experience to feel intuitive and responsive, without dragging down performance.</p>
<h2 id="heading-tech-stack"><strong>Tech Stack</strong></h2>
<p>I’m using a fairly modern stack that suits Foundry’s latest version. I’ve leaned toward tools I am unfamiliar with and want to understand better:</p>
<ul>
<li><p><strong>Foundry VTT v13</strong> – Using the latest API. No backwards compatibility (by design).</p>
</li>
<li><p><strong>TypeScript</strong></p>
</li>
<li><p><strong>Svelte</strong></p>
</li>
<li><p><strong>PixiJS v7</strong> – Which Foundry uses internally, so it’s part of the deal.</p>
</li>
<li><p><strong>Vite</strong></p>
</li>
</ul>
<h2 id="heading-architecture-trying-to-do-things-properly"><strong>Architecture: Trying to Do Things Properly</strong></h2>
<p>With this module, I wanted to be more intentional about structure and scalability. My first module worked, but the code got messy fast. This time I’m following ideas from Clean Architecture and Domain-Driven Design—nothing super strict, but enough to separate concerns and avoid tangling everything together.</p>
<h3 id="heading-project-structure"><strong>Project Structure</strong></h3>
<pre><code class="lang-python">src/
├── application/       <span class="hljs-comment"># Coordinates flow and higher-level logic</span>
│   ├── commands/      <span class="hljs-comment"># Handle specific actions or requests</span>
│   └── factories/     <span class="hljs-comment"># Dependency injection helpers</span>
├── domain/            <span class="hljs-comment"># Core game logic, rules, and decisions</span>
│   ├── entities/      <span class="hljs-comment"># Concepts like Token, Grid, MovementPlan</span>
│   ├── services/      <span class="hljs-comment"># Calculations and validations</span>
│   └── value-objects/ <span class="hljs-comment"># Immutable helpers like Position or Range</span>
├── infrastructure/    <span class="hljs-comment"># Hooks into Foundry and external systems</span>
│   ├── adapters/      <span class="hljs-comment"># Foundry-specific wrappers</span>
│   └── events/        <span class="hljs-comment"># Internal event system</span>
├── presentation/      <span class="hljs-comment"># User interface</span>
│   ├── components/    <span class="hljs-comment"># Svelte-based UI widgets</span>
│   └── styles/        <span class="hljs-comment"># CSS and visual polish</span>
└── lib/               <span class="hljs-comment"># Reusable utilities and helpers</span>
</code></pre>
<h3 id="heading-data-flow-hook-to-ui"><strong>Data Flow: Hook to UI</strong></h3>
<p>Most of the system is event-driven. Rather than having each part of the app call another directly, I’ve set up an <strong>EventBus</strong> so communication stays clean and loosely coupled. Here’s how data generally moves:</p>
<ol>
<li><p><strong>Foundry Hooks → Adapter</strong><br /> Foundry triggers a hook (e.g. token movement), and the FoundryHookAdapter catches it.</p>
</li>
<li><p><strong>Adapter → EventBus</strong><br /> The adapter fires an internal event, so the rest of the app doesn’t need to know anything about Foundry-specific details.</p>
</li>
<li><p><strong>EventBus → Commands and Services</strong><br /> Commands take action based on events, often calling services that implement game logic.</p>
</li>
<li><p><strong>Domain Logic → State Update</strong><br /> Services in the domain layer decide what should happen (e.g., “This path is invalid”), and update the state accordingly.</p>
</li>
<li><p><strong>State → UI</strong><br /> Components listen for state changes and update the interface.</p>
</li>
</ol>
<h3 id="heading-why-this-structure"><strong>Why This Structure?</strong></h3>
<ul>
<li><p><strong>It’s easier to test</strong> – Domain logic is separate from the UI and Foundry, so I can write unit tests without launching the game.</p>
</li>
<li><p><strong>It’s easier to change things</strong> – Since each layer has a clear purpose, I’m not afraid of breaking everything when I tweak something.</p>
</li>
<li><p><strong>It’s easier to think about</strong> – I spend less time wondering <em>where</em> to put new code.</p>
</li>
</ul>
<p>I’m not saying this is the “perfect” architecture for every Foundry module—but for something with a bit of complexity, I hope it will help.</p>
<h2 id="heading-still-early-days"><strong>Still Early Days</strong></h2>
<p>The project is still in its early stages, and I’m learning a lot as I go. There’s plenty left to figure out, and I’m sure I’ll make mistakes. But so far, I’m excited by how it’s shaping up.</p>
<p>If you’re working on something similar, or you’ve tackled movement or pathfinding in Foundry before, I’d love to hear from you. Suggestions, warnings, or even “I tried that and it blew up”—it’s all helpful.</p>
<p>Thanks for reading!</p>
]]></content:encoded></item><item><title><![CDATA[Published My First Foundry VTT Module]]></title><description><![CDATA[Not much to say here—just wanted to brag: I’ve officially published my first Foundry VTT module!
You can check it out on GitHub: Health Arc.]]></description><link>https://hashnode.stonedtroll.com/published-my-first-foundry-vtt-module</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/published-my-first-foundry-vtt-module</guid><category><![CDATA[foundry-vtt]]></category><category><![CDATA[GitHub]]></category><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Thu, 22 May 2025 00:15:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747872672323/30bcc3e6-b6d0-4d30-9b89-c97dbda76a75.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Not much to say here—just wanted to brag: I’ve officially published my first <strong>Foundry VTT</strong> module!</p>
<p>You can check it out on GitHub: <a target="_blank" href="https://github.com/stonedtroll/health-arc">Health Arc</a>.</p>
]]></content:encoded></item><item><title><![CDATA[An Unexpected Party]]></title><description><![CDATA[Hello and welcome!
I’ve been thinking for a while about starting a space where I can share small, playful coding projects inspired by the games I love—and invite you along to build and experiment with me. Whether you’re curious about creating a simpl...]]></description><link>https://hashnode.stonedtroll.com/an-unexpected-party</link><guid isPermaLink="true">https://hashnode.stonedtroll.com/an-unexpected-party</guid><dc:creator><![CDATA[stonedtroll]]></dc:creator><pubDate>Sun, 04 May 2025 20:30:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1746390335604/0fbb5568-3438-4d31-917a-4d2d0d493fc6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello and welcome!</p>
<p>I’ve been thinking for a while about starting a space where I can share small, playful coding projects inspired by the games I love—and invite you along to build and experiment with me. Whether you’re curious about creating a simple dungeon generator, scripting an AI opponent, or just learning how to blend code and creativity, this blog will be our testing ground.</p>
<p>The idea is to keep things light and approachable. I’ll post short tutorials, quick challenges, and bite-sized examples that you can follow in an hour or two. No grand, daunting frameworks—just fun snippets and experiments that spark new ideas and help you practise coding in a gaming context.</p>
<p>Best of all, I want this to be a collaborative lab. Share your tweaks and variations, suggest new experiment ideas, or show off the tiny project you just finished. I’ll highlight interesting community contributions and share feedback so we’re all learning together.</p>
<p>Stay tuned for our first coding quest—coming soon! Feel free to comment below with project ideas or questions, and let’s see what we can build, one small step at a time.</p>
]]></content:encoded></item></channel></rss>