<?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: Mejzun</title>
    <description>The latest articles on DEV Community by Mejzun (@mejzun).</description>
    <link>https://dev.to/mejzun</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%2F4159663%2F2b00c708-3d2f-4694-8db5-51aa057df3a6.png</url>
      <title>DEV Community: Mejzun</title>
      <link>https://dev.to/mejzun</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mejzun"/>
    <language>en</language>
    <item>
      <title>Devlog #1: I built a backlog tracker because I kept forgetting what to play</title>
      <dc:creator>Mejzun</dc:creator>
      <pubDate>Mon, 19 Oct 2026 17:41:52 +0000</pubDate>
      <link>https://dev.to/mejzun/devlog-1-i-built-a-backlog-tracker-because-i-kept-forgetting-what-to-play-4f3p</link>
      <guid>https://dev.to/mejzun/devlog-1-i-built-a-backlog-tracker-because-i-kept-forgetting-what-to-play-4f3p</guid>
      <description>&lt;p&gt;I kept forgetting which games I planned to play. So I built a simple backlog: what I'm playing, what's next, what I've finished.&lt;/p&gt;

&lt;p&gt;That was the whole idea. Here's how it grew into &lt;a href="https://nxto.app/?utm_source=devto&amp;amp;utm_medium=devlog" rel="noopener noreferrer"&gt;NXTO&lt;/a&gt;, and what I learned on the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: A list that works
&lt;/h2&gt;

&lt;p&gt;The first version did one thing: three lists. Playing, planned, finished. No accounts to connect, no clever features. Just somewhere to put games so I'd stop losing them in notes, wishlists and my own memory.&lt;/p&gt;

&lt;p&gt;It solved the problem. But once I was tracking finished games, a new question showed up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: "What should I play next?"
&lt;/h2&gt;

&lt;p&gt;Having a history of what I'd finished made recommendations the obvious next feature. And I had a specific reason to build my own: I own games on several platforms, and Steam's recommendations can't see what I played elsewhere. Every store only knows its own corner of my library.&lt;/p&gt;

&lt;p&gt;So NXTO recommends based on &lt;em&gt;everything&lt;/em&gt; I've played, with my ratings as the signal. (I wrote up the technical side of that, including why my first version suggested junk, &lt;a href="https://dev.to/mejzun/why-my-game-recommender-kept-suggesting-junk-and-how-idf-weighting-fixed-it-3aep"&gt;here&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Sharing it
&lt;/h2&gt;

&lt;p&gt;Once I had this working for myself, I wanted to share it. I put it online on a random domain I already owned, nothing polished, just a link I could send to people.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: People signed up
&lt;/h2&gt;

&lt;p&gt;To my surprise, people started registering. That meant it needed a proper home, so I bought nxto.app.&lt;/p&gt;

&lt;p&gt;Hosting costs money, so I looked for a way to cover it without putting up a paywall. I added a Buy Me a Coffee link, and a price comparison for game keys: open a game and NXTO shows where it's cheapest (Eneba, G2A, Instant Gaming, Kinguin), converted to your currency. Some of those links earn me a small commission, and you never pay more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Honest numbers
&lt;/h2&gt;

&lt;p&gt;Since the first signup in May:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;79&lt;/strong&gt; accounts, &lt;strong&gt;64&lt;/strong&gt; of them have added games&lt;/li&gt;
&lt;li&gt;about &lt;strong&gt;10,400&lt;/strong&gt; games tracked in total&lt;/li&gt;
&lt;li&gt;a catalog of around &lt;strong&gt;150,000&lt;/strong&gt; games to search from&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm building this in the open, with a public ideas page where you can tell me what to build next: &lt;a href="https://nxto.app/ideas?utm_source=devto&amp;amp;utm_medium=devlog" rel="noopener noreferrer"&gt;nxto.app/ideas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you track a backlog, what's the one feature you'd want? And how do you decide what to play next?&lt;/p&gt;

</description>
      <category>devlog</category>
      <category>webdev</category>
      <category>programming</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Nxto story #1: I kept forgetting which games i planned to play. So i build a simple backlog to track what i'm playnig, what i plan to play and what i've finished. #buildinginpublic #indiedev #gamingbacklog</title>
      <dc:creator>Mejzun</dc:creator>
      <pubDate>Mon, 19 Oct 2026 17:23:31 +0000</pubDate>
      <link>https://dev.to/mejzun/nxto-story-1-i-kept-forgetting-which-games-i-planned-to-play-so-i-build-a-simple-backlog-to-4c16</link>
      <guid>https://dev.to/mejzun/nxto-story-1-i-kept-forgetting-which-games-i-planned-to-play-so-i-build-a-simple-backlog-to-4c16</guid>
      <description></description>
    </item>
    <item>
      <title>Why my game recommender kept suggesting junk (and how IDF weighting fixed it)</title>
      <dc:creator>Mejzun</dc:creator>
      <pubDate>Mon, 19 Oct 2026 17:22:12 +0000</pubDate>
      <link>https://dev.to/mejzun/why-my-game-recommender-kept-suggesting-junk-and-how-idf-weighting-fixed-it-3aep</link>
      <guid>https://dev.to/mejzun/why-my-game-recommender-kept-suggesting-junk-and-how-idf-weighting-fixed-it-3aep</guid>
      <description>&lt;p&gt;I play on several platforms, but every store only recommends games based on what I did &lt;em&gt;there&lt;/em&gt;. Steam had no idea what I'd finished elsewhere, so its suggestions kept missing. I wanted one place that knows my whole library, so I built it: &lt;a href="https://nxto.app/?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;NXTO&lt;/a&gt;, a backlog tracker with its own recommendations.&lt;/p&gt;

&lt;p&gt;The stack is boring on purpose: Vue 3, Express, SQLite via &lt;code&gt;better-sqlite3&lt;/code&gt;. Game metadata and tags come from RAWG. The interesting part was making the recommendations not suck.&lt;/p&gt;

&lt;h2&gt;
  
  
  First attempt: Jaccard on tags
&lt;/h2&gt;

&lt;p&gt;The obvious approach: each game has tags, and two games are similar if their tag sets overlap. Jaccard similarity does exactly that.&lt;/p&gt;

&lt;p&gt;It looked fine until I read the results. Games matched on filler tags like &lt;code&gt;2d&lt;/code&gt;, &lt;code&gt;atmospheric&lt;/code&gt; and &lt;code&gt;rpg&lt;/code&gt;, which are shared by thousands of titles. The tags that actually define a game, like &lt;code&gt;farming&lt;/code&gt; or &lt;code&gt;souls-like&lt;/code&gt;, were drowned out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 1: IDF weighting
&lt;/h2&gt;

&lt;p&gt;Borrowing from search: a rare tag should count more than a common one. I weight every tag by inverse document frequency and compare games as vectors with cosine similarity. Two games sharing &lt;code&gt;souls-like&lt;/code&gt; now look far more alike than two games sharing &lt;code&gt;2d&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 2: the long tail of junk tags
&lt;/h2&gt;

&lt;p&gt;IDF created a new problem. The catalog has about 48k distinct tags, and 90% of them occur fewer than 10 times: typos, one-off labels, joke tags. Under plain IDF those rare tags score &lt;em&gt;higher&lt;/em&gt; than any real tag. One tag with a document frequency of 1 got a weight of 8.5 and hijacked the cosine.&lt;/p&gt;

&lt;p&gt;The fix is a minimum document frequency (&lt;code&gt;MIN_DF = 5&lt;/code&gt;). Anything below the floor is dropped from the vocabulary entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fix 3: ratings are signal, not just "finished"
&lt;/h2&gt;

&lt;p&gt;Finishing a game doesn't mean you liked it. I turn the user's rating into a taste weight:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rating&lt;/th&gt;
&lt;th&gt;Weight&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5★&lt;/td&gt;
&lt;td&gt;+2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4★&lt;/td&gt;
&lt;td&gt;+1.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3★&lt;/td&gt;
&lt;td&gt;+0.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2★&lt;/td&gt;
&lt;td&gt;-1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1★&lt;/td&gt;
&lt;td&gt;-2.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;unrated&lt;/td&gt;
&lt;td&gt;+0.8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;3★ means "fine, not a signal", and 1-2★ actively push the taste vector &lt;em&gt;away&lt;/em&gt; from similar games. A user's profile is the weighted sum of their games' tag vectors.&lt;/p&gt;

&lt;p&gt;I also only rank games with at least 10 ratings. Below that, the catalog is full of unrated jam entries that no ranking can order honestly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching without serving stale results
&lt;/h2&gt;

&lt;p&gt;Scoring a whole catalog per request is expensive, so I cache the sorted pool per user. The key includes &lt;code&gt;MAX(updated_at)&lt;/code&gt; &lt;em&gt;and&lt;/em&gt; the row count for the user's games. Both are needed. &lt;code&gt;updated_at&lt;/code&gt; has one-second resolution, and deleting a game doesn't move the maximum at all, so a timestamp-only key would keep serving a pool that still contains the game you just removed.&lt;/p&gt;

&lt;p&gt;I also bump an &lt;code&gt;ALGO_VERSION&lt;/code&gt; in the key whenever scoring changes, so a deploy never serves pools built by the old algorithm.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd do differently
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Look at the output early. The tag problem was invisible in the code and obvious in the results.&lt;/li&gt;
&lt;li&gt;Treat the vocabulary as data to clean, not just math to tune.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you track a backlog, I'd love to know what it recommends for you. And if you've built a recommender, what did you do about noisy tags?&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://nxto.app/?utm_source=devto&amp;amp;utm_medium=article" rel="noopener noreferrer"&gt;nxto.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>buildinpublic</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>ive made game recommendation app nxto.app, it base on your game backlog and ur rating</title>
      <dc:creator>Mejzun</dc:creator>
      <pubDate>Sat, 03 Oct 2026 11:43:50 +0000</pubDate>
      <link>https://dev.to/mejzun/ive-made-game-recommendation-app-nxtoapp-it-base-on-your-game-backlog-and-ur-rating-3d88</link>
      <guid>https://dev.to/mejzun/ive-made-game-recommendation-app-nxtoapp-it-base-on-your-game-backlog-and-ur-rating-3d88</guid>
      <description></description>
    </item>
  </channel>
</rss>
