<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Path Protocol (Eric Silver)</title>
    <description>The latest articles on DEV Community by Path Protocol (Eric Silver) (@pathprotocol).</description>
    <link>https://dev.to/pathprotocol</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4083941%2F5312f0bb-451b-4ff4-a728-62dae97f291d.png</url>
      <title>DEV Community: Path Protocol (Eric Silver)</title>
      <link>https://dev.to/pathprotocol</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pathprotocol"/>
    <language>en</language>
    <item>
      <title>Build your first theme and course in the Theme Workshop</title>
      <dc:creator>Path Protocol (Eric Silver)</dc:creator>
      <pubDate>Tue, 18 Aug 2026 22:01:30 +0000</pubDate>
      <link>https://dev.to/pathprotocol/build-your-first-theme-and-course-in-the-theme-workshop-51b0</link>
      <guid>https://dev.to/pathprotocol/build-your-first-theme-and-course-in-the-theme-workshop-51b0</guid>
      <description>&lt;h1&gt;
  
  
  Build your first theme and course in the Theme Workshop
&lt;/h1&gt;

&lt;p&gt;Path Protocol is an open-source browser precision game — 100 levels, MIT licensed. But the part I'm most excited for people to try is the &lt;strong&gt;Theme Workshop&lt;/strong&gt;: a built-in editor for creating your own themes and courses.&lt;/p&gt;

&lt;p&gt;This tutorial walks you through creating your first theme + course from start to finish and publishing it. No prior game-dev experience needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Register and open the Theme Workshop
&lt;/h2&gt;

&lt;p&gt;Create an account (username, email, password), then open the &lt;strong&gt;Theme Workshop&lt;/strong&gt; from the main menu. On first use you'll be asked to choose the official campaign or an enabled public theme as your starting point.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create a demo theme and level
&lt;/h2&gt;

&lt;p&gt;Use &lt;strong&gt;Create demo theme and level&lt;/strong&gt;. This clones the default campaign and appends a showcase hole. "Cloned" here means the &lt;strong&gt;level JSON only&lt;/strong&gt; — the geometry and rules are copied, not the visual assets. That's an important detail: the game keeps collision geometry and presentation separate.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Edit the course
&lt;/h2&gt;

&lt;p&gt;The editor works on a 10-unit grid in a 1600 × 900 logical world.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resize&lt;/strong&gt; an object by dragging its edge/corner handles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Right-click&lt;/strong&gt; (or Shift+F10) for image, sound, and JSON actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add obstacles&lt;/strong&gt; from the Kenney Course Builder palette — fairway, green, ramp, and hazard templates. You can reshape them after placement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set the arena boundary&lt;/strong&gt; to a rounded rectangle, ellipse, or polygon.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Assign visuals
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pick a &lt;strong&gt;GLB model&lt;/strong&gt; from the 126-model Kenney Minigolf catalog (optional &lt;code&gt;model3dId&lt;/code&gt;). The geometry stays JSON-owned — the model is just presentation.&lt;/li&gt;
&lt;li&gt;Replace an object's &lt;strong&gt;image or sound&lt;/strong&gt; via the media browser, which supports recursive folders, search, preview, and provenance.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Validate and save
&lt;/h2&gt;

&lt;p&gt;Before a level is accepted, it passes &lt;strong&gt;schema validation&lt;/strong&gt; plus generated-course gameplay checks. Invalid levels are rejected — this is what keeps community content safe and consistent. Fix what the validator flags and save.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Playtest
&lt;/h2&gt;

&lt;p&gt;Run the level and watch the token-center trail. This shows the actual collision path your ball takes, which is the ground truth for how the course plays.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Publish and share
&lt;/h2&gt;

&lt;p&gt;Go live as a &lt;strong&gt;public theme&lt;/strong&gt; (moderation exists; the default campaign is read-only). Then copy the link and share it with the community.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;What will you build?&lt;/strong&gt; I'd genuinely love to see what courses people come up with — a wild obstacle, a themed arena, a brutal par-3. If you publish one, drop the link in the comments.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Play:&lt;/strong&gt; &lt;a href="https://app.inkandquill.io/protocol/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=open_source_launch" rel="noopener noreferrer"&gt;https://app.inkandquill.io/protocol/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=open_source_launch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/argentquest/protocol" rel="noopener noreferrer"&gt;https://github.com/argentquest/protocol&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>beginners</category>
      <category>gamedev</category>
      <category>opensource</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a deterministic browser game engine</title>
      <dc:creator>Path Protocol (Eric Silver)</dc:creator>
      <pubDate>Tue, 18 Aug 2026 21:58:59 +0000</pubDate>
      <link>https://dev.to/pathprotocol/build-a-deterministic-browser-game-engine-50j0</link>
      <guid>https://dev.to/pathprotocol/build-a-deterministic-browser-game-engine-50j0</guid>
      <description>&lt;p&gt;I built an open-source browser precision game called &lt;strong&gt;Path Protocol&lt;/strong&gt; — 100 levels, a Theme Workshop for authoring your own courses, MIT licensed. Along the way, one constraint shaped every architectural decision: &lt;strong&gt;levels must replay identically so scores are comparable.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That single requirement turns determinism from a nice-to-have into the product itself. If two players run the same level and the physics drifts, the leaderboard is meaningless. Here's how I structured the engine to make that work, and what I'd do again.&lt;/p&gt;

&lt;h2&gt;
  
  
  The game loop: two clocks, not one
&lt;/h2&gt;

&lt;p&gt;The most important decision was separating the &lt;strong&gt;simulation clock&lt;/strong&gt; from the &lt;strong&gt;render clock&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;requestAnimationFrame&lt;/code&gt; fires when the browser is ready to paint — which varies with monitor refresh rate, background tabs, and system load. If the simulation runs on that clock, the same level plays differently on a 60 Hz vs 144 Hz display.&lt;/p&gt;

&lt;p&gt;Instead, the engine runs a &lt;strong&gt;fixed 60 Hz step&lt;/strong&gt; with an accumulator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;STEP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;250&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// clamp to avoid spiral of death&lt;/span&gt;
  &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;dt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;STEP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;STEP&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// simulation advances in fixed increments&lt;/span&gt;
    &lt;span class="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="nx"&gt;STEP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;         &lt;span class="c1"&gt;// rendering can happen at any rate&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The simulation only ever advances in fixed &lt;code&gt;STEP&lt;/code&gt; increments. Rendering happens as often as the browser allows, but it never changes the game state. This is what makes replays deterministic and scores comparable.&lt;/p&gt;

&lt;p&gt;The level layout is also &lt;strong&gt;seeded&lt;/strong&gt;: the same seed produces the same start position, targets, pickups, and hazards. No randomness leaks into the simulation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ownership: the engine never imports React, Three.js, or the DOM
&lt;/h2&gt;

&lt;p&gt;The cleanest boundary I drew was that the &lt;strong&gt;engine is framework-neutral&lt;/strong&gt;. It doesn't know React exists, doesn't touch Three.js, and never reads the DOM.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React&lt;/strong&gt; owns the menus, HUD, and authoring UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three.js&lt;/strong&gt; owns presentation — rendering the arena.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The engine&lt;/strong&gt; owns movement, collision, scoring, and targets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The renderer exposes a thin surface to the engine: &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;resize&lt;/code&gt;, &lt;code&gt;screenToWorld&lt;/code&gt;, and a few others. The engine calls into it, never the other way around.&lt;/p&gt;

&lt;p&gt;This separation made the engine trivially testable. I could run the entire simulation headless in Vitest — no browser, no WebGL — and assert that a given input produces a given outcome. That's the property that makes deterministic gameplay trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collision and scoring live in contracts, not visual assets
&lt;/h2&gt;

&lt;p&gt;A common trap is deriving collision geometry from visual asset bounds. I avoided that by keeping &lt;strong&gt;collision geometry in JSON&lt;/strong&gt;, separate from the rendered meshes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Collision uses token shapes with &lt;strong&gt;swept tests&lt;/strong&gt; to avoid tunneling at high speed.&lt;/li&gt;
&lt;li&gt;Penalty and restart rules are explicit.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;scoring formula lives in exactly one module&lt;/strong&gt; — there's no second copy to drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This matters for the Theme Workshop too: the same JSON contracts that power the player-facing levels also power community-authored courses. Before any level is accepted, it passes &lt;strong&gt;schema validation&lt;/strong&gt;. That's how an open authoring system stays safe and consistent.&lt;/p&gt;

&lt;h2&gt;
  
  
  What AI-assisted development actually changed
&lt;/h2&gt;

&lt;p&gt;I want to be honest here, because it's easy to overstate. AI helped me move quickly between idea → code → tests → docs. That iteration speed was real and valuable.&lt;/p&gt;

&lt;p&gt;But the hard part stayed hard: &lt;strong&gt;defining the rules.&lt;/strong&gt; Determinism, collision boundaries, scoring ownership, persistence, security, and what the Theme Workshop should allow — those were decisions I had to make deliberately. The AI was a fast pair-programmer, not a substitute for the architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it and contribute
&lt;/h2&gt;

&lt;p&gt;The project is open source under MIT. If you're curious about the fixed-step engine, the collision contracts, or the authoring system, the code is all there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Play:&lt;/strong&gt; &lt;a href="https://app.inkandquill.io/protocol/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=open_source_launch" rel="noopener noreferrer"&gt;https://app.inkandquill.io/protocol/?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=open_source_launch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/argentquest/protocol" rel="noopener noreferrer"&gt;https://github.com/argentquest/protocol&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One question to end with: &lt;strong&gt;what's the first thing you'd want to see in a deterministic game engine's test suite?&lt;/strong&gt; I'd love to hear how others approach replayability.&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>gamedev</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
