<?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: Hiroshi TK</title>
    <description>The latest articles on DEV Community by Hiroshi TK (@hiroshi_takamura_c851fe71).</description>
    <link>https://dev.to/hiroshi_takamura_c851fe71</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%2F3844767%2Ffaccdba7-ad99-4d0a-a1d0-70c04234a705.jpg</url>
      <title>DEV Community: Hiroshi TK</title>
      <link>https://dev.to/hiroshi_takamura_c851fe71</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hiroshi_takamura_c851fe71"/>
    <language>en</language>
    <item>
      <title>Keep crafting sparks inside the inventory slot’s visual budget</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 19 Oct 2026 08:01:05 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/keep-crafting-sparks-inside-the-inventory-slots-visual-budget-117o</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/keep-crafting-sparks-inside-the-inventory-slots-visual-budget-117o</guid>
      <description>&lt;p&gt;This post specifies a bounded effect and host integration; the art values are proposed targets rather than results from a supplied effect bundle.&lt;/p&gt;

&lt;p&gt;A crafting success cue belongs to a specific inventory slot. If its particles spill across item counts or nearby controls, the effect makes the result harder to read. The integration should bound both the event count and the visual area.&lt;/p&gt;

&lt;p&gt;Start with one successful crafting transaction and one slot anchor. Do not trigger the effect when crafting begins, because a rejected request should not look like a completed item.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use success identity, not button activity
&lt;/h2&gt;

&lt;p&gt;A double click can create repeated UI callbacks even when the application accepts only one craft. Drive the cue from the confirmed transaction identity and ignore repeated delivery of the same success event.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCraftCue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;play&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastTransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;confirmed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;transactionId&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;transactionId&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;lastTransaction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;lastTransaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;transactionId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&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;This intentionally small controller remembers only the most recent transaction. If older events can arrive out of order, use a bounded ID cache or an authoritative event sequence instead. Do not claim general network deduplication from a one-value memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Author a restrained burst
&lt;/h2&gt;

&lt;p&gt;A proposed first asset uses eight particles, no continuous emission, a maximum lifetime of 0.3 seconds, and an upward-biased spread. Keep the brightest area above the slot center, with a short fade before particles reach the neighboring label. These are design targets for review, not measured runtime performance.&lt;/p&gt;

&lt;p&gt;Use a distinct effect ID such as &lt;code&gt;craft-slot-spark&lt;/code&gt;. Export for PixiJS and inspect the support report. A web game particle editor can make this visual envelope easy to revise; &lt;a href="https://nixiefx.com/pixijs-particle-effects/" rel="noopener noreferrer"&gt;NixieFX's PixiJS workflow&lt;/a&gt; explains the bundle path to the host application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Convert coordinates at the boundary
&lt;/h2&gt;

&lt;p&gt;The slot may live inside a scrolling or scaled container. Obtain its anchor in the effect layer's local coordinates before spawning the cue. If the slot scrolls out of view, skip the decorative effect while still updating the item count and success state.&lt;/p&gt;

&lt;p&gt;Choose one policy for overlapping crafts. For example, replace the existing cue for that slot instead of adding unlimited new instances. That bounds visual density during rapid crafting without changing the number of successfully crafted items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Confirmed craft -&amp;gt; update inventory state
               -&amp;gt; update visible count and success label
               -&amp;gt; reduced motion? keep static confirmation
               -&amp;gt; visible slot? convert anchor to VFX-layer coordinates
               -&amp;gt; replace that slot's previous cue
               -&amp;gt; play one verified bounded burst
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make the result inspectable
&lt;/h2&gt;

&lt;p&gt;Capture the actual Pixi screen with the item count and adjacent slot visible. Include the effect source and host integration with the post, so another developer can reproduce the envelope rather than judging only a cropped image.&lt;/p&gt;

&lt;p&gt;Test one craft, a repeated event, rapid distinct crafts, a scrolled slot, and reduced motion. After all bursts finish, confirm that the host removes finished instances. On screen teardown, release the owned resources even if a burst is still active.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits worth preserving in the write-up
&lt;/h2&gt;

&lt;p&gt;This controller is not the inventory transaction system. The particle effect cannot confirm a purchase, award an item, or prove a server operation succeeded. Those facts come from application state.&lt;/p&gt;

&lt;p&gt;This guide does not establish a device performance budget. Profile the actual asset in the intended layout. Unsupported settings are those blocked by the export's Pixi report; any partial support needs a specific explanation after the asset is available. Publish the visual result only after those checks, and distinguish the tested source from the proposed art targets.&lt;/p&gt;

</description>
      <category>pixijs</category>
      <category>gamedev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>A quest-completion marker needs a persistent state after the animation</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:59:15 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-quest-completion-marker-needs-a-persistent-state-after-the-animation-2m5c</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-quest-completion-marker-needs-a-persistent-state-after-the-animation-2m5c</guid>
      <description>&lt;p&gt;This is a proposed integration recipe, not a claim of a completed runtime test.&lt;/p&gt;

&lt;p&gt;A quest marker should still communicate completion after its particles disappear. Treat the effect as a short acknowledgment of a state change, while the completed icon and text remain the authoritative UI.&lt;/p&gt;

&lt;p&gt;The sequence in this example is deliberately small: update the quest state, show the completed marker immediately, optionally play one decorative burst, and clean up the effect when it finishes. The animation must not delay reward eligibility or hide the completed state from keyboard and assistive-technology users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deduplicate the completion event
&lt;/h2&gt;

&lt;p&gt;A reconnect or repeated server message can announce the same quest completion twice. Use an identifier for the completion event rather than assuming each callback represents a new achievement.&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="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;makeCompletionHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;onComplete&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;handled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;handled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;handled&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;onComplete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&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;Keep that set within the appropriate session or quest-screen lifetime. A long-running application needs a bounded retention policy or an authoritative completion version, not an unbounded global set. The example isolates the deduplication rule without prescribing the server's event model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Put timing in the asset contract
&lt;/h2&gt;

&lt;p&gt;Use a one-shot marker asset with a proposed 0.45-second maximum particle lifetime and no looping emitter. The persistent check icon should appear at event receipt, not at the end of that lifetime. The exact visual envelope needs review in the game; the value here is an art target rather than a measured result.&lt;/p&gt;

&lt;p&gt;A web game particle editor is useful for adjusting the appearance independently of the quest logic. &lt;a href="https://nixiefx.com/pixijs-particle-effects/" rel="noopener noreferrer"&gt;NixieFX's PixiJS guide&lt;/a&gt; describes the export and runtime integration path. Create a distinct &lt;code&gt;quest-complete&lt;/code&gt; effect, validate it for Pixi, and keep the source alongside the exported bundle.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;On a new completion event:
1. Update the persistent completed icon and label.
2. Announce completion once through the host's accessible UI.
3. If reduced motion is enabled, skip the particles.
4. Otherwise create the verified one-shot at the marker position.
5. Remove the finished instance through the renderer's cleanup API.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These steps are host instructions. The particle runtime does not supply the quest state, semantic label, or screen-reader announcement for a canvas UI. Provide those through the application's accessible interface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the cue out of the reading path
&lt;/h2&gt;

&lt;p&gt;Place the effect behind or beside the marker, with enough separation from the quest title to preserve readability. Test long titles and the smallest supported viewport. If the marker lives inside a transformed Pixi container, compute its position in the effect layer's coordinate space; a global position copied into a local layer can drift.&lt;/p&gt;

&lt;p&gt;For a reproducible visual check, freeze the UI layout, use a fixed seed, and capture the marker at the same elapsed time. Do not describe a screenshot from the editor as proof of the host integration. The runtime screenshot needs to come from the actual Pixi screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check the cases that expose the boundary
&lt;/h2&gt;

&lt;p&gt;Send the same event twice and verify that only one cue occurs. Send a different completion and verify that it can produce its own cue. Enable reduced motion and confirm that the completed state and announcement still appear. Leave the screen during the burst and confirm that teardown removes the effect without changing quest data.&lt;/p&gt;

&lt;p&gt;The code in this post covers event deduplication, not a complete game or a verified exported effect. Inspect the actual Pixi support report for unsupported or approximated authoring settings. Do not claim that lighting, depth, or other Three-specific presentation transfers unchanged. The recipe is complete only when the source asset, host integration, and visual check agree.&lt;/p&gt;

</description>
      <category>pixijs</category>
      <category>gamedev</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Send back the delivery, keep the task: a concrete rework loop</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 19 Oct 2026 07:35:00 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/send-back-the-delivery-keep-the-task-a-concrete-rework-loop-463k</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/send-back-the-delivery-keep-the-task-a-concrete-rework-loop-463k</guid>
      <description>&lt;p&gt;This worked handoff uses a synthetic example.&lt;/p&gt;

&lt;p&gt;A rejected delivery does not automatically mean a new task is needed. If the requested outcome is unchanged and the same runner can correct the problem, opening another ticket splits the acceptance criteria from the evidence that failed them.&lt;/p&gt;

&lt;p&gt;Suppose the task is to preserve the order of records in a CSV export. An agent-assisted patch sorts them alphabetically instead. The output looks tidy, but it violates the original contract. The useful review response names that mismatch and requests proof of correction on the existing task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the rejection against a criterion
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Criterion C1: exported rows retain input order.
Observed mismatch: the implementation sorts by display name.
Example input IDs: [42, 7, 19]
Required output IDs: [42, 7, 19]
Rework: remove sorting from this export path; preserve field escaping.
Proof: add an order-preservation assertion and rerun the existing suite.
Scope: no new ordering preference or export UI changes.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is concrete enough for the runner to reproduce. It does not require guessing what “wrong ordering” means, and it does not expand the task into a configurable sorting feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the transition that matches ownership
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://wagglet.com/blog/wagglet-workflow-request-draft-ticket-delivery" rel="noopener noreferrer"&gt;Wagglet's workflow&lt;/a&gt;, sending a delivery back returns the task to Claimed with the same runner. Reopening returns it to Open and clears the claim. Both preserve earlier evidence, but they make different ownership decisions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Delivered attempt A
  -&amp;gt; review: C1 failed, preserve input order
  -&amp;gt; send back: same runner, rework attempt
  -&amp;gt; corrected implementation + new evidence
  -&amp;gt; Delivered attempt B
  -&amp;gt; reviewer checks C1 and regression coverage
  -&amp;gt; accept, or request a specific remaining correction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep the old report available for context. Make clear that it is no longer the standing answer. Otherwise, a reviewer can accidentally inspect the earlier screenshot or test result while reading the corrected implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the agent a bounded rework brief
&lt;/h2&gt;

&lt;p&gt;The human author or reviewer prepares the correction request. The runner executes it with their own authorized tools. The agent receives the current task context and the review feedback, then proposes and checks the repair. A qualified reviewer judges the new evidence rather than accepting the agent's confidence as proof.&lt;/p&gt;

&lt;p&gt;For the synthetic export example, a small regression fixture can make the correction visible:&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;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;19&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;expectedIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="c1"&gt;// Wire this assertion to the real export-and-parse path in your test suite.&lt;/span&gt;
&lt;span class="c1"&gt;// assert.deepEqual(parseCsv(exportCsv(input)).map(r =&amp;gt; Number(r.id)), expectedIds);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The commented assertion is an integration instruction, not a runnable claim about functions supplied by this post. Use the actual serializer and parser in the repository. A test that merely copies the input array would not exercise the defect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Report the correction by criterion
&lt;/h2&gt;

&lt;p&gt;The new delivery should identify the tested revision, the removed ordering behavior, the regression assertion, and the actual run result. It should also say whether existing escaping checks ran. Preserving order while breaking quoted fields is not an acceptable correction.&lt;/p&gt;

&lt;p&gt;A compact report can use three sentences: “C1 is addressed by removing the sort in the export path. The new test sends IDs 42, 7, and 19 through the serializer and verifies their parsed order. The attached run output and diff refer to the recorded revision.” Only use those sentences once the described work actually exists.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know when separate work is justified
&lt;/h2&gt;

&lt;p&gt;If review reveals a new requirement, such as a user-selectable sort order, the author should decide whether it belongs in the current contract. Do not quietly add it to the repair. Likewise, if the current runner lacks the required access or expertise, reopen for a new authorized runner rather than leaving ownership ambiguous.&lt;/p&gt;

&lt;p&gt;Human supervised AI execution benefits from this distinction. Rework preserves the original outcome and corrects the evidence or implementation. New work changes the outcome. Keeping that boundary explicit makes the history easier to read and the next review easier to conduct.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Wall-impact sparks: test the normal before tuning the glow</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Thu, 15 Oct 2026 06:46:36 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/wall-impact-sparks-test-the-normal-before-tuning-the-glow-19hb</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/wall-impact-sparks-test-the-normal-before-tuning-the-glow-19hb</guid>
      <description>&lt;p&gt;A laser impact needs two inputs from the game: a hit position and an outward surface normal. The particle effect should consume those inputs. It should not invent a collision result from a bright spot on a wall.&lt;/p&gt;

&lt;p&gt;This small Three.js demo uses a fixed planar wall facing positive Z and a synthetic hit at its center. It emits 32 unlit particles and pauses after 18 fixed simulation steps so the direction is easy to inspect. The screenshot shows that constructed test, not a raycast from a shipped game.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with an axis you can name
&lt;/h2&gt;

&lt;p&gt;The authored velocity range points outward along positive Z: X and Y each range from -0.8 to 0.8, while Z ranges from 0.4 to 1.1. Lifetime is 1.2 seconds. Continuous emission is zero. A small positive offset keeps the burst origin just in front of the wall.&lt;/p&gt;

&lt;p&gt;In a real integration, transform a mesh-local hit normal into world space correctly before using it. A normal is a direction, not a position; translating it as though it were a point is a common orientation bug. Nonuniform scale requires the proper normal transformation.&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;const&lt;/span&gt; &lt;span class="nx"&gt;outward&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hitNormal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;normalize&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;orientation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Quaternion&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setFromUnitVectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;outward&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;angles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Euler&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;setFromQuaternion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;orientation&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;origin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;hitPoint&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;addScaledVector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outward&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.02&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;burst&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;angles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;angles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;angles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;14&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;burst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emitBurst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emitters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;effect&lt;/code&gt; here is an already prepared definition with the stated zero-rate emitter. Load a validated runtime bundle in a game. The fixed-wall demo uses an authoring definition to keep the experiment self-contained.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify the simple case before rotating the wall
&lt;/h2&gt;

&lt;p&gt;On the test wall the outward normal is &lt;code&gt;[0,0,1]&lt;/code&gt;, so the quaternion is the identity. This is a useful baseline: particles should move into positive Z from an origin at Z=0.02. It is not evidence that every rotated or scaled wall has been tested.&lt;/p&gt;

&lt;p&gt;The live lab prints the first debug particle position and active count. Inspect those alongside the screenshot. If the particle motion is correct but the picture looks wrong, investigate camera framing, transparency, depth, and scale before changing the collision normal.&lt;/p&gt;

&lt;p&gt;The source below gives the critical emitter settings. Build them on a default effect, mount a ThreeVfxRenderer in a scene, and update it once per frame in seconds.&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;const&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;effect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;emitters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&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="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rateValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;point&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;scalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vector&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;velocity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Make teardown part of the demonstration
&lt;/h2&gt;

&lt;p&gt;Remove the effect after its particles finish, or reuse it through an explicit ownership policy. An active looping emitter with a zero continuous rate can still exist after the visible burst is gone; invisibility is not the same as disposal. The lab's Destroy instances button removes the created instances and reports the remaining count.&lt;/p&gt;

&lt;p&gt;When the scene itself leaves, destroy the VFX renderer, release scene-owned GPU resources, and remove any event listeners or animation-loop callbacks owned by that scene. Do not keep the old renderer alive behind a newly mounted view.&lt;/p&gt;

&lt;p&gt;A web game VFX editor can provide the authored appearance, while the host owns contact detection and lifecycle. The &lt;a href="https://nixiefx.com/threejs-runtime/" rel="noopener noreferrer"&gt;NixieFX Three.js runtime reference&lt;/a&gt; documents the adapter calls used in this boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;The demonstration does not implement raycasting, ricochet, damage, decals, surface-material selection, or collision response for the emitted particles. It verifies one known normal and a visible burst. Test rotated walls and transformed parents separately before generalizing the result.&lt;/p&gt;

&lt;p&gt;Preview bloom is not exported host postprocessing. The recipe is unlit and does not need mesh-surface emission. Those choices also avoid features that PixiJS does not support, but the screenshot is still a Three.js result rather than a cross-renderer visual comparison. GPU frame time and mobile performance remain separate measurements.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82i4p43bjdokiwtkew9s.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F82i4p43bjdokiwtkew9s.png" alt="Three.js wall-impact burst paused at frame 18, with 32 active particles and an outward positive-Z position" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gamedev</category>
    </item>
    <item>
      <title>Review a level-tool script through a safe fixture</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Thu, 15 Oct 2026 06:34:38 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/review-a-level-tool-script-through-a-safe-fixture-12j0</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/review-a-level-tool-script-through-a-safe-fixture-12j0</guid>
      <description>&lt;p&gt;A level designer can verify a tool's output without being asked to certify unfamiliar source code. An engineer can review that source without deciding whether the output matches the designer's intent. A useful cross functional AI workflow gives each reviewer a specific surface to inspect.&lt;/p&gt;

&lt;p&gt;Here is a small example: a script should report duplicate spawn-point identifiers in a level JSON file. It must not repair the level automatically. Reporting is a good first boundary because the input can stay unchanged and the expected output can be written before implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a disposable project
&lt;/h2&gt;

&lt;p&gt;Create a folder containing only the sample below. Do not point an early tool at the studio's level library. The synthetic fixture contains two spawn points named &lt;code&gt;gate&lt;/code&gt; and one named &lt;code&gt;well&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"spawns"&lt;/span&gt;&lt;span class="p"&gt;:[{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"gate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"well"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;},{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"gate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"x"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;"y"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}]}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save it as &lt;code&gt;sample.json&lt;/code&gt;. A successful report should identify &lt;code&gt;gate&lt;/code&gt; once, with a count of two. The script should return a nonzero exit code when duplicates are found so a later pipeline can distinguish an issue from a clean result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the agent a bounded task
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Input: one explicitly supplied JSON file in the sample folder
Output: duplicate identifiers and their counts, sorted by identifier
Exit: 0 for clean data, 1 for duplicates, 2 for malformed input
Allowed: read that file; print a report
Forbidden: rewrite levels, recurse directories, install dependencies
Cases: duplicate ID, unique IDs, missing spawns, invalid ID
Reviewer A: level designer checks the report against the fixture
Reviewer B: engineer reviews parsing, errors, and filesystem behavior
Stop: any request to change the actual level schema
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The author prepares the fixture and expected report. An authorized runner executes the tool in this disposable folder with their own tools. The agent can help implement or explain the code; the runner records the exact command and observed result.&lt;/p&gt;

&lt;h2&gt;
  
  
  A complete reporting script
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;check-spawns.mjs&lt;/code&gt; and run &lt;code&gt;node check-spawns.mjs sample.json&lt;/code&gt;.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;readFileSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;node:fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Supply one JSON file&lt;/span&gt;&lt;span class="dl"&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;level&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawns&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spawns must be an array&lt;/span&gt;&lt;span class="dl"&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;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;for &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;spawn&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawns&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Every spawn needs a nonempty string id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&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="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&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;duplicates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(([,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;duplicates&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;duplicates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exitCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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 expected duplicate payload is &lt;code&gt;{"duplicates":[["gate",2]]}&lt;/code&gt;. Whitespace in the printed JSON is not significant. Identifier comparison is exact and case-sensitive: &lt;code&gt;Gate&lt;/code&gt; and &lt;code&gt;gate&lt;/code&gt; remain different values. If the game treats them as equivalent, that is a schema decision to settle before changing this script.&lt;/p&gt;

&lt;h2&gt;
  
  
  Split the review into two concrete checks
&lt;/h2&gt;

&lt;p&gt;The designer checks the sample data against the report: which markers appear twice, whether a clean sample produces an empty list, and whether the output is understandable without reading a stack trace. A screenshot of the report beside the sample level can help discussion, but the fixture and command are the reproducible evidence.&lt;/p&gt;

&lt;p&gt;The engineer checks that the program only reads the explicitly supplied file, does not execute input, distinguishes malformed data from duplicate data, and has no unexpected write path. This example is small enough to inspect directly. Extending it to arbitrary large or untrusted files needs separate limits and review; a sample-folder workflow is not a security sandbox.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://wagglet.com/blog/meaningful-work-with-human-ai-pairs" rel="noopener noreferrer"&gt;Wagglet discussion of meaningful work in human–AI pairs&lt;/a&gt; is relevant because the useful division of labor follows expertise, not a blanket assumption that the person running an agent can approve every result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deliver evidence with the revision
&lt;/h2&gt;

&lt;p&gt;Return the script, fixtures, command outputs, exit codes, and an unchanged-input check. The designer's acceptance and the engineer's code review should refer to the same revision. Installing the tool into the studio pipeline is a separate release decision, with an owner for failures and rollback.&lt;/p&gt;

&lt;p&gt;This script deliberately does not validate coordinates, enforce a complete level schema, or repair duplicates. Those are potential next tasks. Keeping them outside the first delivery gives both reviewers a result they can actually judge.&lt;/p&gt;

</description>
      <category>gamedev</category>
    </item>
    <item>
      <title>A portable handoff contract for teammates using different AI tools</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Thu, 15 Oct 2026 05:51:10 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-portable-handoff-contract-for-teammates-using-different-ai-tools-4ige</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-portable-handoff-contract-for-teammates-using-different-ai-tools-4ige</guid>
      <description>&lt;p&gt;A useful AI task handoff for teams should work when one developer uses a terminal agent and another uses an editor assistant. The transferable part is the task contract: inputs, allowed changes, required evidence, and a reviewer. The conversation history is optional context.&lt;/p&gt;

&lt;p&gt;Here is a practical template for a small repository change: reject a malformed configuration value with a clear error before the application starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Define the boundary before assigning a runner
&lt;/h2&gt;

&lt;p&gt;The component owner prepares the request. For this example, configuration accepts a positive integer for a local worker count. A blank value should retain the existing default. A non-integer string should fail with a useful message. The author must confirm those requirements against the actual application before anyone edits it.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reject invalid worker-count configuration before startup&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;config parser and focused parser tests&lt;/span&gt;
  &lt;span class="na"&gt;excluded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deployment, credentials, queue architecture&lt;/span&gt;
&lt;span class="na"&gt;inputs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;record the real base commit&lt;/span&gt;
  &lt;span class="na"&gt;config_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;replace with the actual key&lt;/span&gt;
  &lt;span class="na"&gt;reproduction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;supply a synthetic invalid value&lt;/span&gt;
&lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;omitted value preserves the current default&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;valid positive integer preserves behavior&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;zero, negative, and non-integer values are rejected&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;error names the key without printing secret configuration&lt;/span&gt;
&lt;span class="na"&gt;stop_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;the parser contract conflicts with documented behavior&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;the change requires a production configuration update&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;unrelated failures prevent a trustworthy comparison&lt;/span&gt;
&lt;span class="s"&gt;~~~&lt;/span&gt;

&lt;span class="s"&gt;These are proposed acceptance cases. They are not assertions that a particular repository already behaves this way.&lt;/span&gt;

&lt;span class="c1"&gt;## 2. Apply an eligibility gate, then compare fit&lt;/span&gt;

&lt;span class="s"&gt;Access is a gate. The runner must already be authorized to read the repository and use the required environment. A teammate with a powerful model but no repository permission is not eligible merely because someone else can paste them a token.&lt;/span&gt;

&lt;span class="s"&gt;After access, compare expertise and available tools. For this parser task, choose someone who can distinguish a parsing regression from an unrelated build failure. Their agent must be able to inspect the code and run the project's documented tests. Browser-only chat can help explain a proposed change, but cannot itself demonstrate that local tests ran.&lt;/span&gt;

&lt;span class="s"&gt;Suppose Ren has authorized repository access and the relevant configuration knowledge, but only a text chat. Ada has the same access, a terminal agent, and familiarity with the parser tests. Ada can run this task, while Ren can clarify the expected error message. If Ada cannot explain a failed boundary case, the task needs the component owner again; repeated prompting is not a substitute for understanding the requirement.&lt;/span&gt;

&lt;span class="c1"&gt;## 3. Give the runner a small evidence protocol&lt;/span&gt;

&lt;span class="s"&gt;The runner records the base revision and checks for existing work before changes. They run the documented reproduction, capture the actual error, and ask the agent to identify the responsible code. The first proposed diff should stay within the stated boundary.&lt;/span&gt;

&lt;span class="s"&gt;~~~text&lt;/span&gt;
&lt;span class="na"&gt;Before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;command, exit code, observed output, base revision&lt;/span&gt;
&lt;span class="na"&gt;Change&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;files and reason each file is necessary&lt;/span&gt;
&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;same reproduction, focused tests, actual exit codes&lt;/span&gt;
&lt;span class="na"&gt;Uncertainty&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;checks not run and why&lt;/span&gt;
&lt;span class="na"&gt;Review&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;commit reference and named acceptance owner&lt;/span&gt;
&lt;span class="s"&gt;~~~&lt;/span&gt;

&lt;span class="s"&gt;Keep machine-generated explanations separate from observations. “The model says validation is fixed” is a hypothesis. A command and its output are evidence that a check ran. The reviewer still needs to assess whether that check covers the intended failure.&lt;/span&gt;

&lt;span class="c1"&gt;## 4. Hand back a result, including an honest non-result&lt;/span&gt;

&lt;span class="s"&gt;The author prepares the technical brief. The runner executes with their own authorized tools and supervises the checks. A qualified reviewer inspects the diff and decides whether the acceptance cases are met. Deployment remains a separate decision when the task excludes it.&lt;/span&gt;

&lt;span class="s"&gt;If the runner discovers that a worker count of zero deliberately means automatic sizing, they should stop and return that fact. The template was wrong for this repository. The correct action is to revise the requirement, not to change working behavior to satisfy an invented test.&lt;/span&gt;

&lt;span class="s"&gt;The [Wagglet explanation of task handoffs](https://wagglet.com/blog/close-team-skill-gaps-with-ai-task-handoffs) provides the broader preparation-and-review model. This template applies it to a specific configuration change without requiring teammates to share accounts or standardize on one assistant.&lt;/span&gt;

&lt;span class="s"&gt;Before accepting the work, verify the recorded revision, reproduce the named cases, inspect the error for accidental configuration disclosure, and check that no deployment or unrelated cleanup slipped into the diff. The template helps structure evidence; it cannot guarantee a correct implementation or replace domain review.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>ai</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Footstep dust in Three.js with a pool of four effects</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:53:44 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/footstep-dust-in-threejs-with-a-pool-of-four-effects-3d21</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/footstep-dust-in-threejs-with-a-pool-of-four-effects-3d21</guid>
      <description>&lt;p&gt;A footstep effect has two separate rates: how often the character asks for a puff, and how many particles each puff emits. Keeping those separate makes it possible to budget a repeated effect without tying it to the display refresh rate.&lt;/p&gt;

&lt;p&gt;This NixieFX tutorial uses an intentionally simple character proxy, a moving box, with a dust request every 15 simulation frames. At a fixed step of 1/60 second, that is four requests per simulated second. Each request restarts one available effect containing a 12-particle burst.&lt;/p&gt;

&lt;h2&gt;
  
  
  The effect contract
&lt;/h2&gt;

&lt;p&gt;The tested scene uses nixie-fx 0.1.20 and Three.js. The emitter uses procedural unlit billboards, world-space simulation, no continuous emission, a burst at time zero, and a particle lifetime of 0.7 seconds. The effect timeline lasts 0.8 seconds; the emitter's emission duration is 0.05 seconds. There are no texture or mesh downloads.&lt;/p&gt;

&lt;p&gt;That short emission duration matters. A pool member is available only after its effect is inactive. Leaving a long emitter duration on a short visual puff can keep the pool occupied after the visible particles have gone away.&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;const&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;vfx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dustDefinition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;autoStart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;seed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;requests&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="nx"&gt;reused&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="nx"&gt;dropped&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;function&lt;/span&gt; &lt;span class="nf"&gt;onFootstep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="o"&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;puff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;puff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;dropped&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;puff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setTransform&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;puff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;restart&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;reused&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// In this test harness, frame advances at a fixed simulation step.&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;frame&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;15&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="nf"&gt;onFootstep&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;characterX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;vfx&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="mi"&gt;1&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="nx"&gt;renderer&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="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fragment assumes a constructed renderer and the dust definition described above. In an actual game, trigger on the animation's foot-contact event instead of a frame counter. Update the owning renderer once per simulation step; do not also update its instances individually.&lt;/p&gt;

&lt;p&gt;The position belongs to the contact at emission time. Moving an active puff to follow the character would create a different effect. The test moves only an available member immediately before restarting it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the run measured
&lt;/h2&gt;

&lt;p&gt;In one Chrome run on macOS, 180 simulation frames produced 12 requests, 12 pool reuses, zero dropped requests, and four retained effect instances. The final frame contained 24 active particles. The recorded p95 CPU duration around the runtime update was 2.0 ms, while the p95 animation-frame interval was 17.2 ms.&lt;/p&gt;

&lt;p&gt;These are observations from a three-second demonstration with other browser tabs open. They include startup samples and debug-transform capture. They are not GPU measurements, a mobile-device budget, or evidence that pooling is faster than allocating a fresh instance. The useful functional result is narrower: the four-member pool served the requested cadence without allocating another effect instance after setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Saturation is a behavior to choose
&lt;/h2&gt;

&lt;p&gt;This implementation drops a cosmetic puff when the pool is full. That avoids stealing an active instance and visibly cutting off its particles. A different game may choose a larger pool or allow a controlled fallback allocation. Measure the number of dropped requests so the decision is visible.&lt;/p&gt;

&lt;p&gt;Four members are a test parameter, not a universal recommendation. A faster character, multiple characters, longer particle lifetimes, or a slower completion condition can change occupancy. Test those cases separately before selecting the production capacity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits and cleanup
&lt;/h2&gt;

&lt;p&gt;The runtime reported the tested Three.js effect as supported with no warnings or blockers. This example does not implement ground collision, terrain normals, animated character feet, lighting, or mesh particles. Those settings were not validated by this run and should not be inferred from the result. The &lt;a href="https://nixiefx.com/threejs-runtime/" rel="noopener noreferrer"&gt;Three.js runtime documentation&lt;/a&gt; covers integration and backend support checks.&lt;/p&gt;

&lt;p&gt;Remove every retained instance when the owning scene is released, or destroy the renderer if that scene owns it. An inactive effect is still a retained instance. The pool has to be bounded and its lifetime explicit even when nothing is visible.&lt;/p&gt;

</description>
      <category>threejs</category>
      <category>javascript</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Rank the work you can verify, not the tokens you can spend</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Wed, 14 Oct 2026 11:53:31 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/rank-the-work-you-can-verify-not-the-tokens-you-can-spend-1815</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/rank-the-work-you-can-verify-not-the-tokens-you-can-spend-1815</guid>
      <description>&lt;p&gt;The example below is hypothetical and does not report a production result.&lt;/p&gt;

&lt;p&gt;An AI task handoff for teams needs a queue that rewards useful outcomes. Token use measures an input. It cannot tell you whether a migration was necessary, a bug was fixed, or a reviewer can reproduce the result.&lt;/p&gt;

&lt;p&gt;Use four fields before assigning work: impact, risk, readiness, and verification. Keep the last three visible instead of hiding every judgment inside a single priority score.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with gates
&lt;/h2&gt;

&lt;p&gt;Readiness means the runner has the necessary repository access, environment instructions, and a bounded request. Verification means someone can describe the evidence required for acceptance. If either is missing, put the task in preparation. A high-impact request does not become executable because it earned a large number.&lt;/p&gt;

&lt;p&gt;Risk describes the potential cost of a mistake. A public typo correction and a billing migration should not share an approval route. High-risk work needs its specialist and release controls before it enters the ready queue.&lt;/p&gt;

&lt;p&gt;Among ready tasks, rank impact first and use expected review effort as a tie-breaker. This is a starting rubric, not a universal scoring formula:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Low&lt;/th&gt;
&lt;th&gt;Medium&lt;/th&gt;
&lt;th&gt;High&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Impact&lt;/td&gt;
&lt;td&gt;Local convenience&lt;/td&gt;
&lt;td&gt;Repeated team friction&lt;/td&gt;
&lt;td&gt;User-facing failure or blocker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Risk&lt;/td&gt;
&lt;td&gt;Reversible text change&lt;/td&gt;
&lt;td&gt;Bounded behavior change&lt;/td&gt;
&lt;td&gt;Data, access, or release consequences&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Readiness&lt;/td&gt;
&lt;td&gt;Missing owner or access&lt;/td&gt;
&lt;td&gt;One unresolved dependency&lt;/td&gt;
&lt;td&gt;Scope, access, and environment ready&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Verification&lt;/td&gt;
&lt;td&gt;Subjective request&lt;/td&gt;
&lt;td&gt;Evidence partly specified&lt;/td&gt;
&lt;td&gt;Named checks and reviewer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Copy a task card
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;outcome&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export button stays disabled while an export is running&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export panel and its existing interaction tests&lt;/span&gt;
&lt;span class="na"&gt;excluded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export API, file format, unrelated styling&lt;/span&gt;
&lt;span class="na"&gt;impact&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Repeated duplicate export requests&lt;/span&gt;
&lt;span class="na"&gt;risk&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Medium; changes a user interaction&lt;/span&gt;
&lt;span class="na"&gt;prepared_by&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Product engineer&lt;/span&gt;
&lt;span class="na"&gt;runner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Teammate with authorized repository and agent access&lt;/span&gt;
&lt;span class="na"&gt;reviewer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export-panel maintainer&lt;/span&gt;
&lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Second click during an export starts no additional request&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Button becomes available after success or failure&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Keyboard activation follows the same rule&lt;/span&gt;
&lt;span class="na"&gt;evidence&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Focused diff&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Reproduction steps and observed outcomes&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Test commands, results, and any skipped checks&lt;/span&gt;
&lt;span class="na"&gt;stop_when&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Fix requires changing the export API contract&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The author prepares the card and checks that the requested behavior is actually desired. The runner executes it with their own authorized tools and access. The maintainer judges the evidence. A deployment owner decides whether and when the accepted change ships. These can be overlapping people on a small team, but the decisions should still be explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work one handoff
&lt;/h2&gt;

&lt;p&gt;Imagine three requests: polish a tooltip, prevent duplicate exports, and redesign the export API. The tooltip is ready and low risk but has limited impact. The duplicate-request fix has a clear failure and a bounded test. The API redesign has an important goal but no compatibility decision.&lt;/p&gt;

&lt;p&gt;Prepare the redesign before assigning it. Put the bounded fix first among ready work. Keep the tooltip available for a smaller work window. Nothing in that ordering depends on which request consumes the most tokens.&lt;/p&gt;

&lt;p&gt;If the runner discovers that the duplicate originates in the server rather than the panel, they should stop and return the evidence. That is useful progress even without a patch. Rewarding only merged changes would push them toward a superficial client-side fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Review the outcome and the rubric
&lt;/h2&gt;

&lt;p&gt;A reviewer should be able to repeat the relevant checks without reconstructing a long agent conversation. Record a verdict, the evidence used, and any remaining limits. Do not turn a passing test into a claim that every export path is safe.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://wagglet.com/blog/gamification-ai-work-bounties-rewards" rel="noopener noreferrer"&gt;Wagglet discussion of bounties and rewards&lt;/a&gt; is a useful context for designing incentives around accepted work. This template is an independent example, not a description of an automatic scoring feature.&lt;/p&gt;

&lt;p&gt;Try the rubric on a small queue. If apparently ready tasks repeatedly need clarification, improve preparation. If review dominates the work, tighten scope. Treat those observations as workflow feedback, not a ranking of people's value.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>productivity</category>
      <category>softwareengineering</category>
    </item>
    <item>
      <title>A localization handoff that design, QA, and engineering can all use</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Tue, 13 Oct 2026 07:49:24 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-localization-handoff-that-design-qa-and-engineering-can-all-use-5fj5</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-localization-handoff-that-design-qa-and-engineering-can-all-use-5fj5</guid>
      <description>&lt;p&gt;AI disclosure: This tutorial was generated with AI. The reward dialog is a hypothetical example; no production screenshot or test result is claimed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Describe the failure at the string level
&lt;/h2&gt;

&lt;p&gt;A localization issue often arrives as “German breaks the popup.” That report mixes several decisions: whether the translation is correct, whether the layout can accommodate it, and whether the right resource reaches the UI. Give each decision an owner before requesting a fix.&lt;/p&gt;

&lt;p&gt;Use a small example: a reward dialog has a button with the English source string “Claim reward.” In the German locale, the approved translation is longer than the available space at the smallest supported viewport. The designer owns the layout rule, a locale reviewer owns the language, and engineering owns how the component applies both.&lt;/p&gt;

&lt;p&gt;Do not shorten the translation solely to fit an arbitrary character count. Characters have different widths, and a short phrase can still be semantically wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a task from this template
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Fix reward-dialog action-label clipping&lt;/span&gt;
&lt;span class="na"&gt;string_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rewards.claim_cta&lt;/span&gt;
&lt;span class="na"&gt;source_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;en&lt;/span&gt;
&lt;span class="na"&gt;source_string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Claim reward&lt;/span&gt;
&lt;span class="na"&gt;target_locale&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;de&lt;/span&gt;
&lt;span class="na"&gt;target_string&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;use the locale reviewer's approved resource value&lt;/span&gt;
&lt;span class="na"&gt;screen&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;daily reward confirmation dialog&lt;/span&gt;
&lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;reward available; no network request in progress&lt;/span&gt;
&lt;span class="na"&gt;viewport&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;smallest supported mobile viewport, exact dimensions required&lt;/span&gt;
&lt;span class="na"&gt;font&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;record actual family, weight, size and fallback behavior&lt;/span&gt;
&lt;span class="na"&gt;context_screenshot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;before&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;attach a real capture showing the whole dialog and clipped label&lt;/span&gt;
  &lt;span class="na"&gt;after&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;capture the same viewport, locale, state and build configuration&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;this dialog's action-label layout&lt;/span&gt;
&lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;translation rewrites, reward logic, global typography changes&lt;/span&gt;
&lt;span class="na"&gt;preparer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;QA with design&lt;/span&gt;
&lt;span class="na"&gt;executor&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;UI engineer using their own authorized development tools&lt;/span&gt;
&lt;span class="na"&gt;reviewers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;locale reviewer&lt;/span&gt;
  &lt;span class="na"&gt;layout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;designer&lt;/span&gt;
  &lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;QA lead&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The screenshot entries are evidence requirements, not links to nonexistent images. Before using this as a real ticket, attach a capture from the affected build and record its revision. Crop out private account information, but retain enough surrounding UI to explain what the button does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Work the handoff in three decisions
&lt;/h2&gt;

&lt;p&gt;First, QA reproduces the clipping and records the locale, device scale, viewport, and loaded font. A fallback font can change the result, so a screenshot without font context is insufficient. QA also checks whether the defect appears before or after the translation resources finish loading.&lt;/p&gt;

&lt;p&gt;Second, design specifies an acceptable layout behavior. For example, permit the action region to grow vertically while preserving the existing minimum touch target and the approved gap to the secondary action. This is an example decision, not a universal prescription. If the product requires a single-line button, design must instead define an approved width strategy or language-review escalation.&lt;/p&gt;

&lt;p&gt;Third, the engineer changes only the relevant component and returns the diff with comparable before/after captures. If the implementation discovers a shared component issue, expand the scope explicitly before changing every dialog in the game.&lt;/p&gt;

&lt;p&gt;An assistant can help find uses of the string key, draft a test matrix, or propose a constrained component change. That is expert supervised AI execution when the human owners provide the context and review the evidence. &lt;a href="https://wagglet.com/blog/ai-native-mobile-game-studio-stack" rel="noopener noreferrer"&gt;Wagglet's studio-stack discussion&lt;/a&gt; provides a related framework for coordinating those roles. It does not make an AI-generated translation an approved resource.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify content and layout separately
&lt;/h2&gt;

&lt;p&gt;Use this acceptance checklist for the example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The exact approved target string renders without clipping or ellipsis.&lt;/li&gt;
&lt;li&gt;The label remains inside the action area at each supported narrow viewport.&lt;/li&gt;
&lt;li&gt;The button still performs the same reward action exactly once.&lt;/li&gt;
&lt;li&gt;English remains readable and the secondary action remains reachable.&lt;/li&gt;
&lt;li&gt;The locale reviewer approves meaning and tone independently of layout.&lt;/li&gt;
&lt;li&gt;QA captures the final state using the same setup as the original report.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add an automated layout assertion if the application exposes suitable bounds. Check the rendered text against its actual containing region after fonts and translations are ready. A character-count check cannot establish that the text fits. For a canvas UI, use the engine's text and container bounds and retain a visual capture; DOM text measurements may not represent the canvas renderer.&lt;/p&gt;

&lt;p&gt;The engineer should record what ran, what failed, and what was not checked. “All locales fixed” is too broad if only English and German were exercised.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the limits visible
&lt;/h2&gt;

&lt;p&gt;Pseudo-localization helps expose constrained layouts, but it does not certify grammar, right-to-left behavior, or cultural suitability. This example does not supply a real failing build or screenshot. Treat it as a reusable handoff recipe and replace the evidence fields when applying it to your game.&lt;/p&gt;

&lt;p&gt;The final acceptance decision belongs to the named reviewers. A clean diff and a plausible screenshot are inputs to that decision, not substitutes for it.&lt;/p&gt;

</description>
      <category>design</category>
      <category>frontend</category>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Budget waterfall mist with particle lifetime before adding density</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Tue, 13 Oct 2026 06:52:00 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/budget-waterfall-mist-with-particle-lifetime-before-adding-density-43n</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/budget-waterfall-mist-with-particle-lifetime-before-adding-density-43n</guid>
      <description>&lt;p&gt;Waterfall mist can consume a surprising amount of a scene's visual budget because it is usually continuous. A burst ends; an ambient emitter remains active while the player explores. The useful first question is how many particles the effect keeps alive, not how dense it looks in the editor.&lt;/p&gt;

&lt;p&gt;This NixieFX tutorial uses a small Three.js fixture: a rectangular waterfall prop, a soft emitter at its base, and a visible runtime readout. The prop is ordinary host geometry. The mist is a NixieFX 0.1.20 billboard effect rendered with Three.js r185.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set the population before tuning the appearance
&lt;/h2&gt;

&lt;p&gt;The emitter creates 24 particles per second, with a lifetime of three seconds and a capacity of 96. Ignoring boundary timing, the expected steady population is approximately 24 × 3 = 72 particles. Capacity is a hard ceiling, not a promise that all 96 particles are always present.&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="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxParticles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;96&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rateValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;initializeParticle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lifetime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;constant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;box&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;emitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;box&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mf"&gt;1.8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code uses &lt;code&gt;createConstantParticleScalar&lt;/code&gt; as &lt;code&gt;constant&lt;/code&gt;. The complete source initializes the remaining fields from &lt;code&gt;createDefaultParticleEffect&lt;/code&gt;, enables a fade over lifetime, and gives each particle a small upward velocity. Depth testing stays enabled and depth writing stays disabled for the translucent billboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Place the effect relative to a readable prop
&lt;/h2&gt;

&lt;p&gt;Place the effect at &lt;code&gt;[0, 0.2, 0]&lt;/code&gt;. The demonstration waterfall sits behind it and supplies a stable scale reference. The scene is deliberately plain: mist density should be readable without a complex material, lighting rig, or postprocessing chain.&lt;/p&gt;

&lt;p&gt;A dark background makes soft particle overlap visible. It can also make an additive effect seem more impressive than it will appear in a bright level, so this fixture uses alpha blending. Test against the actual level colors before treating its appearance as final.&lt;/p&gt;

&lt;p&gt;The emitter does not collide with the waterfall or surrounding terrain. It does not simulate water volume, spray breakup, or moisture. It is a visual layer placed near a prop.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep simulation accounting separate from rendering accounting
&lt;/h2&gt;

&lt;p&gt;Advance the runtime once per fixed simulation step, then render the scene. Do not advance an instance separately when its renderer already owns the update.&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="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="mi"&gt;1&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;vfx&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="mi"&gt;1&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="nx"&gt;accumulator&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&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="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;renderer&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="nx"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The fixture caps the elapsed time added after a long frame. That prevents a large catch-up burst when a tab resumes, but it also means the demo is not a wall-clock simulation under stalls. Its fixed-step sequence is useful for comparisons.&lt;/p&gt;

&lt;p&gt;The readout reports active particles, visible particles, capacity, instanced draw calls, and legacy particle draw calls. These are different quantities. A particle whose alpha is zero at birth may exist in the simulation while contributing nothing visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the observed result carefully
&lt;/h2&gt;

&lt;p&gt;At a recorded simulation time of 60 seconds, the fixture showed 73 active particles, 72 visible particles, capacity 96, and one instanced draw call. The peak active count was 73. The extra particle around the simple 72-particle estimate reflects spawn and lifetime boundaries in the stepped simulation; it is not evidence that the capacity limit failed.&lt;/p&gt;

&lt;p&gt;The runtime's support report was &lt;code&gt;supported&lt;/code&gt;, and its unsupported-feature list was empty for this definition. A separate repeatability check compared two 90-step runs with seed 2444 and found identical particle debug transforms.&lt;/p&gt;

&lt;p&gt;This is not a performance benchmark. A single emitter does not reproduce a full level's overdraw, resolution, effects, or device limits. The particle counter is a useful diagnostic, but it cannot replace a frame capture on the target hardware.&lt;/p&gt;

&lt;h2&gt;
  
  
  Change one budget variable at a time
&lt;/h2&gt;

&lt;p&gt;First hold lifetime at three seconds and adjust the emission rate. Then restore the rate and adjust lifetime. Finally, test billboard size, because larger translucent quads can increase overdraw even when the particle count stays constant.&lt;/p&gt;

&lt;p&gt;Keep the same camera and seed during each comparison. If you add a flipbook, material graph, or other feature, inspect the rendering path again instead of assuming the original draw-call result still applies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://nixiefx.com/threejs-runtime/" rel="noopener noreferrer"&gt;The NixieFX Three.js runtime guide&lt;/a&gt; documents the counters and integration controls used here. A useful ambient effect is one whose visual contribution and resource cost can both be explained.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>javascript</category>
      <category>performance</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>A task record is not an execution contract: a handoff template for coding agents</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Mon, 12 Oct 2026 07:57:20 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/a-task-record-is-not-an-execution-contract-a-handoff-template-for-coding-agents-4bp8</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/a-task-record-is-not-an-execution-contract-a-handoff-template-for-coding-agents-4bp8</guid>
      <description>&lt;p&gt;Disclosure: This draft was generated with AI assistance. The worked example is illustrative and has not been run against a production repository.&lt;/p&gt;

&lt;p&gt;A ticket can accurately describe a bug while leaving the executor unable to start. “CSV export loses filters” tells us what hurts. It does not identify the repository revision, the supported command, the intended output, or the person who can accept the change.&lt;/p&gt;

&lt;p&gt;When comparing task tracking with managed agent execution, compare responsibilities rather than labels. A task tracker can be part of a well-managed execution system. An agent runner can also be poorly managed. The difference is whether the handoff specifies the following four things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compare context, runner, evidence, and acceptance
&lt;/h2&gt;

&lt;p&gt;Context: Can the executor find the exact starting revision, relevant behavior, constraints, and allowed files? A long conversation is not a substitute for a small, current specification.&lt;/p&gt;

&lt;p&gt;Runner: Is there an authorized operator and a known environment? Naming an agent is insufficient if nobody has installed the dependencies or can grant the necessary repository access.&lt;/p&gt;

&lt;p&gt;Evidence: Does delivery identify the patch, actual commands run, results, and untested cases? “Done” is a state label, not a verification record.&lt;/p&gt;

&lt;p&gt;Acceptance: Is a person responsible for deciding whether the result satisfies the requirement? The executor should not silently replace the requested behavior with an easier interpretation.&lt;/p&gt;

&lt;p&gt;These criteria are useful when evaluating project management for coding agents because they apply before a particular tool enters the picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write the execution contract
&lt;/h2&gt;

&lt;p&gt;Here is an original template for an illustrative CSV repair. Values in angle brackets must come from the actual project. Command names are deliberately not invented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;task&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Preserve the selected filters in CSV export&lt;/span&gt;
&lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;repository&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;authorized repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;base_revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified commit&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;reproduction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Select status=open, then export CSV&lt;/span&gt;
  &lt;span class="na"&gt;expected&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export contains exactly the rows matching the filter&lt;/span&gt;
  &lt;span class="na"&gt;fixtures&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;sanitized fixture path&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;allowed&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Export query and focused regression coverage&lt;/span&gt;
  &lt;span class="na"&gt;excluded&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Authentication, schema migrations, unrelated UI changes&lt;/span&gt;
&lt;span class="na"&gt;execution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;operator&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;developer or authorized agent operator&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;setup_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified command from this repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;test_command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;verified command from this repository&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Existing authorized development access only&lt;/span&gt;
&lt;span class="na"&gt;delivery&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;patch_revision&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
  &lt;span class="na"&gt;commands_and_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required&lt;/span&gt;
  &lt;span class="na"&gt;sample_output&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sanitized CSV from the fixture&lt;/span&gt;
  &lt;span class="na"&gt;untested_cases&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;required, even when empty&lt;/span&gt;
&lt;span class="na"&gt;acceptance&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;product_owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Confirms filtering semantics&lt;/span&gt;
  &lt;span class="na"&gt;engineer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Reviews implementation and regression evidence&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Do not paste credentials into that contract. The person executing the task uses their own authorized tools and access. If the environment is unavailable, that is an execution blocker to resolve, not an invitation to share an account.&lt;/p&gt;

&lt;h2&gt;
  
  
  Walk one handoff through the template
&lt;/h2&gt;

&lt;p&gt;The product owner prepares a fixture containing three records: two open and one closed. The expected filtered export contains the two open records. An engineer confirms the expected behavior and identifies the relevant export path.&lt;/p&gt;

&lt;p&gt;The executor first reproduces the failure at the recorded revision. If it does not reproduce, the next useful delivery is the attempted command, environment details, and observed output. Editing code before resolving that mismatch risks fixing a different problem.&lt;/p&gt;

&lt;p&gt;After reproducing the issue, the executor implements a scoped change and adds coverage for the filtered export. The normal unfiltered export is also checked, because repairing one path can narrow the other accidentally. Those are proposed checks; no passing results are claimed here.&lt;/p&gt;

&lt;p&gt;The delivery attaches the patch revision and actual output from the verified test command. The engineer reviews the change. The product owner inspects the sanitized sample and confirms that the selected filters mean what users expect. If either review fails, the same task records the reason and the next attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the tool comparison honest
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://wagglet.com/for/engineering-teams" rel="noopener noreferrer"&gt;Wagglet's engineering-team page&lt;/a&gt; is the assigned product reference for this workflow. The template above is a proposed operating practice, not evidence that any particular platform supplies every field, runner, or verification step automatically.&lt;/p&gt;

&lt;p&gt;A task tracker may already be sufficient if the team supplies the missing execution contract through its development process. A managed execution tool may reduce coordination work, but it still cannot decide an ambiguous product requirement without an acceptance owner.&lt;/p&gt;

&lt;p&gt;The useful comparison is therefore concrete: take one real repair and ask where its context, execution authority, proof, and decision live. Any blank answer identifies work the team still has to do.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>startup</category>
      <category>programming</category>
    </item>
    <item>
      <title>Hand off the feature-flag implementation without handing off the release decision</title>
      <dc:creator>Hiroshi TK</dc:creator>
      <pubDate>Fri, 09 Oct 2026 08:46:50 +0000</pubDate>
      <link>https://dev.to/hiroshi_takamura_c851fe71/hand-off-the-feature-flag-implementation-without-handing-off-the-release-decision-3cge</link>
      <guid>https://dev.to/hiroshi_takamura_c851fe71/hand-off-the-feature-flag-implementation-without-handing-off-the-release-decision-3cge</guid>
      <description>&lt;p&gt;The scenario and rollout values below are illustrative, not results from a production release.&lt;/p&gt;

&lt;p&gt;A feature flag separates deployment from exposure only if the handoff preserves that distinction. “Implement the new checkout behind a flag” leaves several decisions open: who may deploy the code, who may change the flag, and what evidence is needed before more users see it?&lt;/p&gt;

&lt;p&gt;Write those boundaries before assigning the implementation. A developer can prepare a change and return evidence. The release owner still needs a clear decision point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the flag off
&lt;/h2&gt;

&lt;p&gt;Consider a hypothetical checkout summary that recalculates shipping after a user changes an address. The task is to implement the new summary behind &lt;code&gt;checkout_summary_v2&lt;/code&gt;, with the existing behavior retained when the flag is off.&lt;/p&gt;

&lt;p&gt;The product owner defines the expected user behavior. An engineer prepares the repository context, tests, and constraints. The runner executes with their own authorized tools and environment. A reviewer judges the implementation, and the release owner authorizes deployment and exposure changes separately.&lt;/p&gt;

&lt;p&gt;Neither access to a flag dashboard nor a passing test implies permission to enable production traffic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use a brief with separate exit conditions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Feature: checkout_summary_v2
Default: off

Implementation scope:
- Add the alternate summary path behind the flag.
- Preserve the existing path when disabled.
- Do not change payment authorization or order persistence.

Required checks:
- Flag off: existing address-change behavior remains intact.
- Flag on: displayed totals match the approved calculation fixture.
- Flag changes: no duplicate charge or duplicate order request.
- Missing flag configuration: retain the approved safe default.

Delivery package:
Revision, changed files, exact test commands and outputs,
screenshots from the same fixture, known limits.

Implementation acceptance: [named engineering reviewer]
Product acceptance: [named product owner]
Production deployment: [named release owner]
Exposure changes: [named flag owner]

Stop boundary:
Return the reviewed change. Do not deploy or enable production traffic.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a task template, not a record of completed checks. Replace the placeholders with real owners and attach actual evidence before acceptance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the staged rollout a separate decision
&lt;/h2&gt;

&lt;p&gt;An illustrative rollout could progress from internal users to 1%, then 10%, then broader exposure. Those percentages are planning examples, not universal recommendations. The release owner must define observation windows, relevant metrics, and rollback thresholds for the actual service.&lt;/p&gt;

&lt;p&gt;Require explicit approval at each stage. A quiet dashboard over a short interval may simply mean that too few users exercised the feature. Include a minimum useful sample or a representative manual check instead of assuming that elapsed time proves safety.&lt;/p&gt;

&lt;p&gt;For the checkout example, inspect calculation mismatches and failed completion attempts. Also check whether the old path still works when the flag is disabled. Document who may halt the rollout and where that decision is recorded.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make rollback a behavior, not a slogan
&lt;/h2&gt;

&lt;p&gt;Turning a flag off is only a rollback if the old path can still operate with the state produced by the new one. If a migration or irreversible side effect has occurred, disabling exposure may not restore the previous behavior.&lt;/p&gt;

&lt;p&gt;The example deliberately excludes payment and persistence changes to keep the task narrow. If implementation discovers that either must change, stop and revise the brief. Do not stretch a UI task into a transaction-system change without a new review.&lt;/p&gt;

&lt;p&gt;A useful rollback rehearsal records the starting state, the disabling action, and the resulting user behavior. An unexecuted runbook is still a plan, even if the commands look correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the delivery and the approval connected
&lt;/h2&gt;

&lt;p&gt;Teams that manage work in one system need to preserve the difference between “a runner returned a change” and “the accountable owner accepted it.” &lt;a href="https://wagglet.com/blog/wagglet-workflow-request-draft-ticket-delivery" rel="noopener noreferrer"&gt;Wagglet’s request-to-delivery workflow&lt;/a&gt; describes that separation; this brief makes the responsibilities explicit regardless of the tracking tool.&lt;/p&gt;

&lt;p&gt;The reviewer should be able to identify the accepted revision, the evidence supporting it, and any unresolved limitation. The release owner should see the same information before approving exposure. If new evidence invalidates the decision, the task history should explain why the rollout stopped.&lt;/p&gt;

&lt;p&gt;The flag’s default, the delivery’s acceptance, and the release’s approval are three different facts. Write each one down, assign each decision to a person, and let the implementation handoff end at the boundary you actually authorized.&lt;/p&gt;

</description>
      <category>management</category>
      <category>product</category>
      <category>softwaredevelopment</category>
      <category>softwareengineering</category>
    </item>
  </channel>
</rss>
