<?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 brake</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, your name gets a slice on a big wheel, and chat spins it. 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 brakes it
&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;Every small streamer knows the end of a stream. Chat is warm, a few people are hanging out, and there is nobody worth raiding. So you hit End Stream and everyone scatters.&lt;/p&gt;

&lt;p&gt;I got tired of that, so I'm building 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 wheel mid-spin, with chat braking it" 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 instead of nobody.&lt;/li&gt;
&lt;li&gt;Your raid opens a portal on screen, your viewers come through, and your name gets a slice on a big wheel.&lt;/li&gt;
&lt;li&gt;Chat votes on a category, then spins the wheel and mashes !stop to brake it.&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, not a promise. Your odds are your slice of the wheel, 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.&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>
