<?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: Basanoviat</title>
    <description>The latest articles on DEV Community by Basanoviat (@basanoviat).</description>
    <link>https://dev.to/basanoviat</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%2F4166063%2F833086c7-28c7-4b93-a8ad-ff4fd6196930.png</url>
      <title>DEV Community: Basanoviat</title>
      <link>https://dev.to/basanoviat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/basanoviat"/>
    <language>en</language>
    <item>
      <title>The physics of a wheel a whole Twitch chat can stop</title>
      <dc:creator>Basanoviat</dc:creator>
      <pubDate>Mon, 12 Oct 2026 02:36:09 +0000</pubDate>
      <link>https://dev.to/basanoviat/the-physics-of-a-wheel-a-whole-twitch-chat-can-brake-4jf5</link>
      <guid>https://dev.to/basanoviat/the-physics-of-a-wheel-a-whole-twitch-chat-can-brake-4jf5</guid>
      <description>&lt;p&gt;I'm building RaidPort, a Twitch channel that turns raids into a live gameshow for small streamers. You raid in at the end of your stream, and your raid earns a Charge: a slice on a gameshow wheel of raiders. This post is about the wheel itself, because getting it to feel right took longer than anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  It runs on the server
&lt;/h2&gt;

&lt;p&gt;The wheel is simulated on the server in Node.js and TypeScript, many times a second. The overlay in OBS only draws what it is told: the server streams the wheel's angle and speed to it over a WebSocket.&lt;/p&gt;

&lt;p&gt;That split matters. Chat votes from everyone land on one wheel, and the winner is decided in one place that no viewer's browser can touch.&lt;/p&gt;

&lt;h2&gt;
  
  
  A slow wheel is a readable wheel
&lt;/h2&gt;

&lt;p&gt;A real prize wheel slows down fast at first, then crawls. The crawl is the good part, because that is when everyone can read the names going past the pointer. So the friction changes with the wheel's speed: strong while it is flying, gentle once it is crawling.&lt;/p&gt;

&lt;p&gt;Pure exponential slowdown has a catch: it never actually reaches zero, so the wheel would crawl forever. A small steady drain on top makes sure every spin ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chat picks the spin length first
&lt;/h2&gt;

&lt;p&gt;Before the spin, chat votes on whether it should be a fast spin or a slow one, and the result sets how long the wheel coasts if nobody touches it.&lt;/p&gt;

&lt;p&gt;I did not want to tune friction by hand for every length. It turns out the time a spin takes to stop scales cleanly with the friction, so one dry run tells you exactly what friction gives the length you asked for. Pick a length, get that length.&lt;/p&gt;

&lt;h2&gt;
  
  
  Then chat slows it down
&lt;/h2&gt;

&lt;p&gt;During the spin, anyone in chat can type &lt;code&gt;!stop&lt;/code&gt;, and each vote adds friction. The hard part is making that fair for a channel with a handful of people and a channel with hundreds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Per person.&lt;/strong&gt; Each extra vote from the same person counts for less than the one before. Spamming helps a little, never a lot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Across everyone.&lt;/strong&gt; The more votes have already landed, the less each new one adds.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;By audience size.&lt;/strong&gt; In a bigger chat each vote is weaker, but there are more of them. There are limits at both ends.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those limits came from a bug. The audience size was being read from the wrong place: the number of slices on the wheel instead of the number of people who could vote. A big raid against a small wheel got almost full strength per vote from hundreds of people, and the wheel stopped nearly at once, which is exactly what the scaling exists to prevent. The other limit covers the opposite case, so one person alone in chat cannot stop the wheel by themselves.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ghost line
&lt;/h2&gt;

&lt;p&gt;The overlay draws a second, faint speed line: what the wheel would be doing if nobody had typed &lt;code&gt;!stop&lt;/code&gt;. The gap between the two lines is what chat did.&lt;/p&gt;

&lt;p&gt;For that gap to mean anything, the ghost has to slow down by exactly the same rules as the real wheel. For a while it did not. The real wheel had its own copy of the slowdown math, so tuning the shared version quietly changed only the ghost, and the chart showed a gap chat never made. Now there is one copy and both lines go through it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Landing on a name
&lt;/h2&gt;

&lt;p&gt;The wheel only lands on channels that are live. If the slice under the pointer belongs to someone who has gone offline, the win moves to the next live slice, and the wheel eases over to it in under a second so it visibly rests on the channel that actually won.&lt;/p&gt;

&lt;h2&gt;
  
  
  One bug I would warn anyone about
&lt;/h2&gt;

&lt;p&gt;Starting a spin started a fast timer loop. Starting another spin before the first one finished started another, and the old one kept running. After a few rounds the server had several zombie loops and the overlay started to stutter. The fix was one line, stop the old loop first, but it took a long test run to see it.&lt;/p&gt;




&lt;p&gt;I'm one person building this. The portal opens Fall 2026, and if you stream, founding member signups are at &lt;a href="https://raidport.tv/?utm_source=devto&amp;amp;utm_medium=forum&amp;amp;utm_campaign=building&amp;amp;utm_content=forum-long-02" rel="noopener noreferrer"&gt;raidport.tv&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>typescript</category>
      <category>gamedev</category>
      <category>twitch</category>
    </item>
    <item>
      <title>I built a live gameshow for Twitch raids, for small streamers</title>
      <dc:creator>Basanoviat</dc:creator>
      <pubDate>Tue, 06 Oct 2026 10:13:30 +0000</pubDate>
      <link>https://dev.to/basanoviat/i-built-a-live-gameshow-for-twitch-raids-for-small-streamers-4l14</link>
      <guid>https://dev.to/basanoviat/i-built-a-live-gameshow-for-twitch-raids-for-small-streamers-4l14</guid>
      <description>&lt;p&gt;What if the end of your stream was the start of a show? Your chat is warm and up for one more thing, so I built RaidPort: a Twitch channel that turns raids into a live gameshow.&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%2F4p2w5lthsx2fb3f7n0ee.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%2F4p2w5lthsx2fb3f7n0ee.png" alt="The RaidPort gameshow wheel of raiders mid-spin" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How a round plays
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;At the end of your stream, you raid the RaidPort channel.&lt;/li&gt;
&lt;li&gt;Your raid opens a portal on screen, your viewers come through, and your raid earns a Charge: a slice on a gameshow wheel of raiders.&lt;/li&gt;
&lt;li&gt;Chat votes on categories to shape the wheel.&lt;/li&gt;
&lt;li&gt;Whoever the wheel lands on, and is live, gets raided by the whole channel.&lt;/li&gt;
&lt;/ol&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%2Faa3ln3fnfwtgdhfhifw7.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%2Faa3ln3fnfwtgdhfhifw7.png" alt="The portal opening as a raid arrives" width="800" height="450"&gt;&lt;/a&gt;&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%2Fdqkecsx2tlrn3vdez4y2.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%2Fdqkecsx2tlrn3vdez4y2.png" alt="Chat voting on a category before the spin" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's a lottery: the more Charges you've earned, the better your odds, and the wheel only lands on channels that are live.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it isn't
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;No login, no "authorize this app" screen, no bot in your chat. It only uses Twitch's own raid button.&lt;/li&gt;
&lt;li&gt;No fake viewers. Everyone who arrives was watching the show.&lt;/li&gt;
&lt;li&gt;Free, and never pay to win.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Node.js and TypeScript backend with a 120 Hz physics wheel and a round state machine.&lt;/li&gt;
&lt;li&gt;The overlay is PixiJS (WebGL) running as an OBS browser source.&lt;/li&gt;
&lt;li&gt;Twitch EventSub sees a raid land, and the Helix API sends the raid out.&lt;/li&gt;
&lt;li&gt;Postgres keeps track of everyone's slices.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  45 seconds of it
&lt;/h2&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/wi4zt6H_HtU" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I'm one person building this. The portal opens Fall 2026, and if you stream, founding member signups are at &lt;a href="https://raidport.tv/?utm_source=devto&amp;amp;utm_medium=forum&amp;amp;utm_campaign=building&amp;amp;utm_content=forum-long-01" rel="noopener noreferrer"&gt;raidport.tv&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>twitch</category>
      <category>typescript</category>
      <category>streaming</category>
    </item>
  </channel>
</rss>
