<?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: Nuco Z</title>
    <description>The latest articles on DEV Community by Nuco Z (@nuco_z_270906fb0e460592db).</description>
    <link>https://dev.to/nuco_z_270906fb0e460592db</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%2F3629891%2Ff0b9fcae-351e-4316-b5cf-1fdb20a0c398.png</url>
      <title>DEV Community: Nuco Z</title>
      <link>https://dev.to/nuco_z_270906fb0e460592db</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nuco_z_270906fb0e460592db"/>
    <language>en</language>
    <item>
      <title>Building a Low-Cost AI Brainrot Video Pipeline on Cloudflare</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Sat, 18 Jul 2026 10:13:19 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/building-a-low-cost-ai-brainrot-video-pipeline-on-cloudflare-5ego</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/building-a-low-cost-ai-brainrot-video-pipeline-on-cloudflare-5ego</guid>
      <description>&lt;p&gt;Short-form video tools often look like a single button, but the product experience is really a small distributed system. A useful pipeline has to accept messy inputs, turn them into a script, generate media, report progress clearly, and keep the cost of each render predictable.&lt;/p&gt;

&lt;p&gt;I am building &lt;a href="https://brainrotkit.com" rel="noopener noreferrer"&gt;BrainrotKit&lt;/a&gt; around that problem. The goal is not to hide the workflow behind a magic button. The goal is to make each stage understandable enough that a creator can review the result and decide whether it is worth generating the next stage.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start in the browser when the browser is good enough
&lt;/h2&gt;

&lt;p&gt;PDF parsing and OCR do not always need a paid server. A browser can extract text from many PDFs locally, and an OCR library can handle image-based notes without sending the original file to a backend. This reduces latency, lowers storage requirements, and gives users a simpler privacy story.&lt;/p&gt;

&lt;p&gt;The important boundary is quality. If the browser cannot confidently extract the content, the UI should say so and ask for a clearer file. Quietly passing a bad OCR result to a language model only creates a more expensive bad result.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Separate planning from media generation
&lt;/h2&gt;

&lt;p&gt;The text model should produce a compact, structured plan before an image or video model is called. A useful intermediate object contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a one-sentence hook;&lt;/li&gt;
&lt;li&gt;the narration script;&lt;/li&gt;
&lt;li&gt;a visual description for each beat;&lt;/li&gt;
&lt;li&gt;the target duration;&lt;/li&gt;
&lt;li&gt;a short caption and title.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This separation makes retries cheaper. If the image looks wrong, regenerate the image prompt instead of paying to rewrite the entire script. It also makes the system easier to debug because every output has a visible input.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Use a job state machine, not a spinner
&lt;/h2&gt;

&lt;p&gt;Media generation is asynchronous. A request can move through "queued", "planning", "generating-image", "generating-voice", "generating-video", "ready", or "failed". The frontend should display the current stage, an estimated next action, and a useful error when something goes wrong.&lt;/p&gt;

&lt;p&gt;A generic spinner is not enough for a ten-second wait. Users should know whether the system is still planning, waiting for a provider, or retrying a failed asset. This is also where idempotency matters: refreshing the page must not create a second paid job accidentally.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Track credits at the product layer
&lt;/h2&gt;

&lt;p&gt;Provider prices change, so the product should not expose raw API costs as if they were permanent. I prefer a simple credit ledger: each operation reserves credits, the worker records the actual result, and unused reservations are released when a job fails before generation.&lt;/p&gt;

&lt;p&gt;Short drafts are useful here. A five-second render is a cheaper way to validate a prompt than a fifteen-second render, and the UI can make that tradeoff explicit before the user starts.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Keep the user in the review loop
&lt;/h2&gt;

&lt;p&gt;An AI video is not finished just because the provider returned a file. The creator still needs to check pronunciation, pacing, captions, and whether the visual actually supports the idea. The product should make preview, download, retry, and delete actions obvious.&lt;/p&gt;

&lt;p&gt;That is the thinking behind &lt;a href="https://brainrotkit.com" rel="noopener noreferrer"&gt;BrainrotKit&lt;/a&gt;: a focused AI brainrot video workflow for turning text, notes, and PDFs into short-form concepts while keeping the intermediate steps visible. The meme layer can be playful; the engineering underneath should be boring, observable, and cost-aware.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical first release
&lt;/h2&gt;

&lt;p&gt;For a small team, the first production version can stay intentionally narrow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;browser-side extraction for text and PDFs;&lt;/li&gt;
&lt;li&gt;one text model for script planning;&lt;/li&gt;
&lt;li&gt;one image provider and one video provider;&lt;/li&gt;
&lt;li&gt;durable project and credit records;&lt;/li&gt;
&lt;li&gt;clear loading states and failure messages;&lt;/li&gt;
&lt;li&gt;a short export before longer generations.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is enough to learn where users actually get stuck. The first principle is to measure the complete user journey, not just whether an individual model call succeeded. When the workflow is understandable, creators can make better decisions and the platform can improve without wasting their budget on invisible retries.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cloud</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Small Static Game Wiki with Next.js and Cloudflare Workers</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Wed, 01 Jul 2026 03:35:02 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/building-a-small-static-game-wiki-with-nextjs-and-cloudflare-workers-4f27</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/building-a-small-static-game-wiki-with-nextjs-and-cloudflare-workers-4f27</guid>
      <description>&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%2Fn5p592u61ziy5fcvrl1c.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%2Fn5p592u61ziy5fcvrl1c.png" alt="CookieRun Classic Wiki guide hub" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently put together a small static guide hub for CookieRun Classic: &lt;a href="https://crclassic.wiki/" rel="noopener noreferrer"&gt;CRClassic.wiki&lt;/a&gt;. It is a simple content site, but the deployment path had a few details that are easy to miss when combining Next.js static export, Cloudflare Workers Static Assets, sitemap generation, and game-guide SEO.&lt;/p&gt;

&lt;p&gt;This is a short technical note on what ended up mattering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The site shape
&lt;/h2&gt;

&lt;p&gt;The site is not an app dashboard. It is a focused information hub with separate pages for player intent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;codes and redeem steps&lt;/li&gt;
&lt;li&gt;beginner route&lt;/li&gt;
&lt;li&gt;cookie, pet, and treasure tier pages&lt;/li&gt;
&lt;li&gt;PC setup&lt;/li&gt;
&lt;li&gt;reroll and meta notes&lt;/li&gt;
&lt;li&gt;a central wiki hub&lt;/li&gt;
&lt;/ul&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%2Fm9o8tzi7ppuuft8urrn1.webp" 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%2Fm9o8tzi7ppuuft8urrn1.webp" alt="CookieRun Classic beginner guide preview" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That split helps because each URL answers a different question. A player searching for a redeem flow does not need to land on the same page as someone comparing Cookie upgrades.&lt;/p&gt;

&lt;h2&gt;
  
  
  Static export was the right fit
&lt;/h2&gt;

&lt;p&gt;For this kind of site, static output keeps the deployment simple:&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="c1"&gt;// next.config.mjs&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;export&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;unoptimized&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Cloudflare Workers config points directly at the generated &lt;code&gt;out&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json-doc"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cpclassic"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"compatibility_date"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"directory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./out"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"html_handling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"auto-trailing-slash"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"not_found_handling"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"404-page"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&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;h2&gt;
  
  
  The small metadata details mattered
&lt;/h2&gt;

&lt;p&gt;The site needed normal page metadata, but also page-specific Open Graph images so each guide has a relevant preview instead of one generic logo.&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%2Fjkvuc99itassf13zbdmi.webp" 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%2Fjkvuc99itassf13zbdmi.webp" alt="CookieRun Classic cookie tier preview" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A few details I made sure to include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;canonical URLs for every route&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;robots.txt&lt;/code&gt; and &lt;code&gt;sitemap.xml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;max-image-preview: large&lt;/code&gt; for Google image previews&lt;/li&gt;
&lt;li&gt;page-specific &lt;code&gt;og:image&lt;/code&gt; and Twitter card images&lt;/li&gt;
&lt;li&gt;a real favicon instead of relying only on 32px PNG files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The public sitemap is here: &lt;a href="https://crclassic.wiki/sitemap.xml" rel="noopener noreferrer"&gt;https://crclassic.wiki/sitemap.xml&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Content pages need more than lists
&lt;/h2&gt;

&lt;p&gt;For game-guide pages, a plain tier table is rarely enough. The more useful structure is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;who should use this option&lt;/li&gt;
&lt;li&gt;when to upgrade it&lt;/li&gt;
&lt;li&gt;when to stop investing&lt;/li&gt;
&lt;li&gt;what mistakes to avoid&lt;/li&gt;
&lt;li&gt;what related page to read next&lt;/li&gt;
&lt;/ul&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%2Fc0lnsjw5i65uhubwpqeo.webp" 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%2Fc0lnsjw5i65uhubwpqeo.webp" alt="CookieRun Classic treasure upgrade preview" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is the approach I used on the &lt;a href="https://crclassic.wiki/cookie-run-classic-tier-list" rel="noopener noreferrer"&gt;Cookie Run Classic Tier List&lt;/a&gt;: the page includes rankings, but the real value is upgrade logic and account-stage guidance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Takeaway
&lt;/h2&gt;

&lt;p&gt;For a small wiki, the technical stack can stay boring. The hard part is making each page answer a real search intent and making sure crawlers can clearly see the URL, canonical, sitemap entry, image preview, and internal links.&lt;/p&gt;

&lt;p&gt;If you are building a similar static guide hub, I would start with the content architecture first, then wire the metadata and deployment around that structure.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>cookierun</category>
      <category>gamechallenge</category>
    </item>
    <item>
      <title>How I Built a Fan Guide Hub for BOMBANANA!</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Fri, 26 Jun 2026 07:23:19 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/how-i-built-a-fan-guide-hub-for-bombanana-3ga7</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/how-i-built-a-fan-guide-hub-for-bombanana-3ga7</guid>
      <description>&lt;p&gt;I recently put together a fan guide hub for &lt;strong&gt;BOMBANANA!&lt;/strong&gt;, a new co-op bomb defusal game where three players have to coordinate under different communication limits.&lt;/p&gt;

&lt;p&gt;The site is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://bombanana.online/" rel="noopener noreferrer"&gt;https://bombanana.online/&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%2F347atwbqg0fd3o2r83ni.jpg" 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%2F347atwbqg0fd3o2r83ni.jpg" alt="BOMBANANA gameplay" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built it
&lt;/h2&gt;

&lt;p&gt;The game is funny and chaotic, but the learning curve is mostly about communication. New players do not only need a list of rules. They need a content structure that answers practical questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What does each role do?&lt;/li&gt;
&lt;li&gt;Which player should speak first?&lt;/li&gt;
&lt;li&gt;How should the team describe modules?&lt;/li&gt;
&lt;li&gt;What should a beginner team practice in the first session?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That shaped the site architecture more than keyword research alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Content structure
&lt;/h2&gt;

&lt;p&gt;I split the guide into a few core sections:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Role guides: &lt;a href="https://bombanana.online/roles" rel="noopener noreferrer"&gt;https://bombanana.online/roles&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Module guides: &lt;a href="https://bombanana.online/modules" rel="noopener noreferrer"&gt;https://bombanana.online/modules&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;First-session guide: &lt;a href="https://bombanana.online/beginners/how-to-play" rel="noopener noreferrer"&gt;https://bombanana.online/beginners/how-to-play&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Team callouts: &lt;a href="https://bombanana.online/communication/team-callouts" rel="noopener noreferrer"&gt;https://bombanana.online/communication/team-callouts&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal is to make the site useful during actual gameplay, not just readable as a long article.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;For a small game guide site, the best pages are not always generic “ultimate guide” pages. The highest-value pages are often specific resources that players can use immediately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a checklist&lt;/li&gt;
&lt;li&gt;a module walkthrough&lt;/li&gt;
&lt;li&gt;role-specific advice&lt;/li&gt;
&lt;li&gt;short callout systems&lt;/li&gt;
&lt;li&gt;screenshots that match the game state&lt;/li&gt;
&lt;/ul&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%2Fna7mbge35lk7qqtd9r1e.jpg" 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%2Fna7mbge35lk7qqtd9r1e.jpg" alt="Module screenshot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;I am continuing to improve the guide with more screenshots, better internal links, and clearer module pages as more players search for help around the demo and full release.&lt;/p&gt;

&lt;p&gt;If you are building a small content site for a game, my main takeaway is simple: organize by the player’s next decision, not by what looks like a clean blog category.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>gamedev</category>
      <category>seo</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I Built a Task Bar Hero Item Database and Drop Finder</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Tue, 09 Jun 2026 09:37:49 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/i-built-a-task-bar-hero-item-database-and-drop-finder-5cbd</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/i-built-a-task-bar-hero-item-database-and-drop-finder-5cbd</guid>
      <description>&lt;h1&gt;
  
  
  I Built a Wiki for Task Bar Hero After Getting Tired of Looking Up Item Drops
&lt;/h1&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.amazonaws.com%2Fuploads%2Farticles%2Fk3uy6nprj189fayp3ahf.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.amazonaws.com%2Fuploads%2Farticles%2Fk3uy6nprj189fayp3ahf.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;br&gt;
While playing Task Bar Hero, I kept running into the same questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does this item drop?&lt;/li&gt;
&lt;li&gt;Is it tradable?&lt;/li&gt;
&lt;li&gt;Does it actually sell on Steam?&lt;/li&gt;
&lt;li&gt;Is farming it worth the time?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The information existed, but it was scattered across Discord messages, Steam discussions, and spreadsheets.&lt;/p&gt;

&lt;p&gt;So I decided to build a dedicated wiki and tool site.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Goal
&lt;/h2&gt;

&lt;p&gt;I wanted a single place where players could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;search any item&lt;/li&gt;
&lt;li&gt;see drop locations&lt;/li&gt;
&lt;li&gt;check Steam Market availability&lt;/li&gt;
&lt;li&gt;compare farming routes&lt;/li&gt;
&lt;li&gt;access item-specific tools&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project eventually became:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://taskbarhero.nanobananas.me" rel="noopener noreferrer"&gt;https://taskbarhero.nanobananas.me&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Item Database
&lt;/h2&gt;

&lt;p&gt;The first challenge was structuring item data.&lt;/p&gt;

&lt;p&gt;Every item page needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rarity&lt;/li&gt;
&lt;li&gt;level&lt;/li&gt;
&lt;li&gt;category&lt;/li&gt;
&lt;li&gt;drop sources&lt;/li&gt;
&lt;li&gt;market status&lt;/li&gt;
&lt;li&gt;related items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of writing pages manually, I generated them from a structured dataset and created static routes with Next.js.&lt;/p&gt;

&lt;p&gt;Example item page:&lt;/p&gt;

&lt;p&gt;/items/minor-ruby&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Drop Finder
&lt;/h2&gt;

&lt;p&gt;The most-used feature became the Drop Finder.&lt;/p&gt;

&lt;p&gt;Instead of navigating through multiple pages, players can search an item directly and immediately see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;where it drops&lt;/li&gt;
&lt;li&gt;which stages contain it&lt;/li&gt;
&lt;li&gt;farming options&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ended up being much faster than searching through community posts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Steam Market Pages
&lt;/h2&gt;

&lt;p&gt;One unexpected SEO issue involved Steam Market data.&lt;/p&gt;

&lt;p&gt;Some items are technically tradable but have no active market listings.&lt;/p&gt;

&lt;p&gt;Initially I generated market pages for every item.&lt;/p&gt;

&lt;p&gt;The result:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;thousands of low-value pages&lt;/li&gt;
&lt;li&gt;thin content&lt;/li&gt;
&lt;li&gt;poor index quality&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this, I split pages into two categories:&lt;/p&gt;

&lt;h3&gt;
  
  
  Indexed
&lt;/h3&gt;

&lt;p&gt;Items with actual Steam Market data.&lt;/p&gt;

&lt;h3&gt;
  
  
  Noindexed
&lt;/h3&gt;

&lt;p&gt;Items without meaningful market information.&lt;/p&gt;

&lt;p&gt;Users can still access those pages, but search engines are instructed not to index them.&lt;/p&gt;

&lt;p&gt;This significantly improved the quality of pages submitted through the sitemap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multilingual SEO
&lt;/h2&gt;

&lt;p&gt;The site also supports multiple languages.&lt;/p&gt;

&lt;p&gt;One challenge was that English uses the root path:&lt;/p&gt;

&lt;p&gt;/items/minor-ruby&lt;/p&gt;

&lt;p&gt;while other languages use locale prefixes:&lt;/p&gt;

&lt;p&gt;/zh/items/minor-ruby&lt;/p&gt;

&lt;p&gt;To avoid duplicate-content issues I implemented:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;canonical URLs&lt;/li&gt;
&lt;li&gt;hreflang alternates&lt;/li&gt;
&lt;li&gt;locale-specific sitemaps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This keeps language versions connected while allowing search engines to understand the preferred URL structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Next.js&lt;/li&gt;
&lt;li&gt;TypeScript&lt;/li&gt;
&lt;li&gt;Static Generation&lt;/li&gt;
&lt;li&gt;XML Sitemap Generation&lt;/li&gt;
&lt;li&gt;Structured Data&lt;/li&gt;
&lt;li&gt;Canonical URLs&lt;/li&gt;
&lt;li&gt;Hreflang Alternates&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What I'd Improve Next
&lt;/h2&gt;

&lt;p&gt;The current roadmap includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better farming calculators&lt;/li&gt;
&lt;li&gt;richer item relationships&lt;/li&gt;
&lt;li&gt;drop-rate analytics&lt;/li&gt;
&lt;li&gt;player-contributed data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The project started as a small utility for myself, but it's becoming a useful resource for other players as well.&lt;/p&gt;

&lt;p&gt;If you play Task Bar Hero, I'd love to hear what information you find hardest to locate in-game.&lt;br&gt;
That meant internal links, sitemap URLs, canonical URLs, and language switching all had to follow the same rule.&lt;/p&gt;

&lt;p&gt;Why I Built It&lt;br&gt;
Game wiki pages are useful, but I wanted something more decision-focused:&lt;/p&gt;

&lt;p&gt;“Where should I farm this?”&lt;br&gt;
“Does it have a market price?”&lt;br&gt;
“What drops it?”&lt;br&gt;
“What item should I compare it with?”&lt;br&gt;
So the site is more like a database plus a set of small tools.&lt;/p&gt;

&lt;p&gt;What I’m Improving Next&lt;br&gt;
Next things I want to improve:&lt;/p&gt;

&lt;p&gt;better farming route recommendations&lt;br&gt;
more market confidence signals&lt;br&gt;
cleaner guide pages&lt;br&gt;
more item comparison tools&lt;br&gt;
better visual summaries for new players&lt;br&gt;
If you play Task Bar Hero or like game-data tools, feedback is welcome.&lt;/p&gt;

&lt;p&gt;Main site:&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://taskbarhero.nanobananas.me/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=500uv_week" rel="noopener noreferrer"&gt;https://taskbarhero.nanobananas.me/?utm_source=devto&amp;amp;utm_medium=post&amp;amp;utm_campaign=500uv_week&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title># I Built a Cleaner Online Grid Maker Because Most Existing Tools Feel Outdated</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Tue, 19 May 2026 09:11:01 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/-i-built-a-cleaner-online-grid-maker-because-most-existing-tools-feel-outdated-269a</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/-i-built-a-cleaner-online-grid-maker-because-most-existing-tools-feel-outdated-269a</guid>
      <description>&lt;p&gt;I’ve been practicing drawing and reference transfers recently, and I kept running into the same issue:&lt;/p&gt;

&lt;p&gt;Most online grid makers either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;feel outdated&lt;/li&gt;
&lt;li&gt;have poor mobile UX&lt;/li&gt;
&lt;li&gt;generate blurry grids&lt;/li&gt;
&lt;li&gt;overload the UI with unnecessary controls&lt;/li&gt;
&lt;li&gt;or make exporting painful&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I started building my own browser-based grid tool focused on simplicity and speed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I wanted to improve
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Better visual clarity
&lt;/h3&gt;

&lt;p&gt;A lot of existing tools stack too many settings at once.&lt;/p&gt;

&lt;p&gt;I wanted a cleaner workflow where users can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upload an image&lt;/li&gt;
&lt;li&gt;Adjust grid size&lt;/li&gt;
&lt;li&gt;Export instantly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without needing to learn the interface first.&lt;/p&gt;




&lt;h3&gt;
  
  
  Faster canvas rendering
&lt;/h3&gt;

&lt;p&gt;One issue I noticed was that large images + dynamic grids can get laggy quickly in the browser.&lt;/p&gt;

&lt;p&gt;I spent some time optimizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;canvas redraw behavior&lt;/li&gt;
&lt;li&gt;grid overlay rendering&lt;/li&gt;
&lt;li&gt;export sharpness&lt;/li&gt;
&lt;li&gt;responsive scaling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Especially for large portrait references.&lt;/p&gt;




&lt;h3&gt;
  
  
  Better use cases beyond drawing
&lt;/h3&gt;

&lt;p&gt;Interestingly, people started using it for things I didn’t initially expect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Instagram grid planning&lt;/li&gt;
&lt;li&gt;pixel art references&lt;/li&gt;
&lt;li&gt;crochet patterns&lt;/li&gt;
&lt;li&gt;classroom worksheets&lt;/li&gt;
&lt;li&gt;tattoo stencil prep&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which pushed me to make the layout system more flexible.&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.amazonaws.com%2Fuploads%2Farticles%2Fo2evbw9icbmonmurx2vj.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.amazonaws.com%2Fuploads%2Farticles%2Fo2evbw9icbmonmurx2vj.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  UX Lessons I Learned
&lt;/h2&gt;

&lt;p&gt;One thing I underestimated:&lt;/p&gt;

&lt;p&gt;Users care more about &lt;em&gt;clarity&lt;/em&gt; than features.&lt;/p&gt;

&lt;p&gt;Removing friction improved the experience far more than adding advanced options.&lt;/p&gt;

&lt;p&gt;Things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fewer buttons&lt;/li&gt;
&lt;li&gt;clearer spacing&lt;/li&gt;
&lt;li&gt;instant preview updates&lt;/li&gt;
&lt;li&gt;cleaner typography&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;made a bigger difference than “power features”.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current Direction
&lt;/h2&gt;

&lt;p&gt;Right now I’m experimenting with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;better mobile support&lt;/li&gt;
&lt;li&gt;template presets&lt;/li&gt;
&lt;li&gt;sharper exports&lt;/li&gt;
&lt;li&gt;dark mode improvements&lt;/li&gt;
&lt;li&gt;reusable layouts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Still a work in progress, but it’s been fun building something actually useful for creators.&lt;/p&gt;

&lt;p&gt;For anyone curious, the current version is here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gridmakeronline.com/" rel="noopener noreferrer"&gt;https://gridmakeronline.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love feedback from people who work with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;drawing workflows&lt;/li&gt;
&lt;li&gt;canvas tools&lt;/li&gt;
&lt;li&gt;image processing&lt;/li&gt;
&lt;li&gt;creator utilities&lt;/li&gt;
&lt;li&gt;frontend performance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Curious what features you think these kinds of tools still lack today.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>ux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>From Side Project to $500/Month: Building a YouTube Tool as a Solo Developer</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Mon, 09 Mar 2026 03:52:06 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/from-side-project-to-500month-building-a-youtube-tool-as-a-solo-developer-8ok</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/from-side-project-to-500month-building-a-youtube-tool-as-a-solo-developer-8ok</guid>
      <description>&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.amazonaws.com%2Fuploads%2Farticles%2F40u7vk2s714corl59x64.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.amazonaws.com%2Fuploads%2Farticles%2F40u7vk2s714corl59x64.png" alt=" " width="800" height="423"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I built a YouTube subtitle downloader as a side project. After 6 months and a lot of trial and error, I'm finally hitting $500/month. Here is the raw truth about what I learned.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎬 The Origin Story
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;March 2025:&lt;/strong&gt; I was working on a video project and needed to extract subtitles from 50+ YouTube videos. Manual copying? No way.&lt;/p&gt;

&lt;p&gt;I spent 2 hours building a quick Python script to automate it. It worked perfectly. Then I thought: &lt;em&gt;"Others probably need this too."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spoiler:&lt;/strong&gt; That assumption was both right and wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 The Idea Validation
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What I did right:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Searched "youtube subtitle download" - 10K+ monthly searches. ✅&lt;/li&gt;
&lt;li&gt;Checked competitors - they existed (market validation!). ✅&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I did wrong:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Didn't talk to potential users before writing code. ❌&lt;/li&gt;
&lt;li&gt;Assumed people would pay immediately. ❌&lt;/li&gt;
&lt;li&gt;Ignored the "Red Ocean" warning signs. ❌&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lesson 1:&lt;/strong&gt; Competition = validation, but you need a unique angle to stand out.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛠️ Building the MVP
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Week 1-2:&lt;/strong&gt; Basic functionality&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Input URL → Download subtitle&lt;/li&gt;
&lt;li&gt;Tech: Next.js + Python + Vercel&lt;/li&gt;
&lt;li&gt;Cost: $0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Week 3-4:&lt;/strong&gt; The "Feature Creep" mistake&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added 5 different export formats&lt;/li&gt;
&lt;li&gt;Fancy animations&lt;/li&gt;
&lt;li&gt;Dark mode&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Users:&lt;/strong&gt; 0&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lesson 2:&lt;/strong&gt; Ship fast, iterate faster. Nobody cares about dark mode if your core value isn't hitting the mark.&lt;/p&gt;

&lt;h2&gt;
  
  
  📉 The Reality Check
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Month 1 Results:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Traffic: 50 visitors/day (mostly bots)&lt;/li&gt;
&lt;li&gt;Revenue: $0&lt;/li&gt;
&lt;li&gt;Time spent: 80 hours&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; I built a "better mousetrap" in a market full of them. I needed to pivot.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Turning Point:&lt;/strong&gt; I added &lt;strong&gt;AI-powered summarization&lt;/strong&gt;. Suddenly, I wasn't just a "downloader"—I was an AI productivity tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Monetization Strategy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What didn't work:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Paywalls:&lt;/strong&gt; 95% bounce rate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$9.99/mo subscription:&lt;/strong&gt; Too expensive for casual users.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What worked:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Freemium:&lt;/strong&gt; First download is free (no signup). This reduced friction by 80%.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credit system:&lt;/strong&gt; Pay-as-you-go model. Users love flexibility.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Conversion rate:&lt;/strong&gt; 2.5% (Industry average is 2-5%)&lt;/p&gt;

&lt;h2&gt;
  
  
  📊 Growth Tactics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ❌ What Failed:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Paid ads (burned $200, got 2 signups).&lt;/li&gt;
&lt;li&gt;Cold emails (0% response).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ✅ What Worked:
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. SEO Long-tail Keywords&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"how to download youtube subtitles for free"&lt;/li&gt;
&lt;li&gt;Traffic: 60% of my total visitors come from organic search.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Reddit (The "Careful" approach)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answering genuine questions in &lt;code&gt;r/SaaS&lt;/code&gt; and &lt;code&gt;r/Productivity&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Warning:&lt;/strong&gt; Don't be spammy. You will get banned.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Content Marketing&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wrote a 5,000-word "Ultimate Guide to YouTube Subtitles".&lt;/li&gt;
&lt;li&gt;It ranks #3 on Google for specific queries. Traffic: 25%.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  💸 Revenue Breakdown (Month 6)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;th&gt;Revenue&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Individual users&lt;/td&gt;
&lt;td&gt;$320&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API subscriptions&lt;/td&gt;
&lt;td&gt;$100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ads (AdSense)&lt;/td&gt;
&lt;td&gt;$80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$500/mo&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Net profit: ~$435/mo.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎯 What I'd Do Differently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Talk to users FIRST:&lt;/strong&gt; Would've discovered the AI angle in Week 1.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Start with paid from day 1:&lt;/strong&gt; Free users give feedback, paid users give validation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus on ONE channel:&lt;/strong&gt; Don't spread yourself thin across Twitter, LinkedIn, and Reddit. Master one first.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  📈 Key Metrics
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MRR:&lt;/strong&gt; $500&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Churn:&lt;/strong&gt; 15% (Working to improve this)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CAC:&lt;/strong&gt; $12 (mostly organic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LTV:&lt;/strong&gt; $35 (Average user stays 5 months)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🤝 Want to Follow Along?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Check out the tool:&lt;/strong&gt; &lt;a href="https://ytvidhub.com" rel="noopener noreferrer"&gt;ytvidhub.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Questions for you:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;What's your biggest challenge with side projects right now?&lt;/li&gt;
&lt;li&gt;Would you pay for a YouTube AI tool?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Drop your thoughts below! 👇&lt;/p&gt;

&lt;p&gt;&lt;em&gt;P.S. If you're building something, ship it. Imperfect action &amp;gt; perfect inaction.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>startup</category>
      <category>indiehacke</category>
      <category>showdev</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I Built a Bulk YouTube Subtitle Extractor as a Solo Dev — Here's My Tech Stack and What I Learned</title>
      <dc:creator>Nuco Z</dc:creator>
      <pubDate>Fri, 27 Feb 2026 03:11:58 +0000</pubDate>
      <link>https://dev.to/nuco_z_270906fb0e460592db/i-built-a-bulk-youtube-subtitle-extractor-as-a-solo-dev-heres-my-tech-stack-and-what-i-learned-21m6</link>
      <guid>https://dev.to/nuco_z_270906fb0e460592db/i-built-a-bulk-youtube-subtitle-extractor-as-a-solo-dev-heres-my-tech-stack-and-what-i-learned-21m6</guid>
      <description>&lt;p&gt;Every developer has that one side project that starts as a weekend hack and turns into something real. For me, it was a tool to bulk-extract YouTube subtitles.&lt;/p&gt;

&lt;p&gt;It started with a simple frustration: I needed transcripts from an entire YouTube playlist for a research project. YouTube lets you copy transcripts one video at a time. I had 200 videos. That wasn't going to work.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://ytvidhub.com/" rel="noopener noreferrer"&gt;YTVidHub&lt;/a&gt; — a web app that extracts subtitles from YouTube videos, playlists, and entire channels in bulk. Paste a URL, pick your format (SRT, VTT, or TXT), and download everything as a ZIP.&lt;/p&gt;

&lt;p&gt;Here's what the journey looked like from a technical perspective.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Tech Stack
&lt;/h2&gt;

&lt;p&gt;I wanted something that could ship fast, handle server-side rendering for SEO, and scale without DevOps headaches. Here's what I landed on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Framework:&lt;/strong&gt; Next.js 16 (App Router)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language:&lt;/strong&gt; TypeScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Styling:&lt;/strong&gt; Tailwind CSS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL + Prisma ORM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth:&lt;/strong&gt; JWT-based (custom, no third-party provider)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Features:&lt;/strong&gt; DeepSeek API for video summarization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Payments:&lt;/strong&gt; Stripe&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting:&lt;/strong&gt; Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;i18n:&lt;/strong&gt; next-intl (4 languages)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Next.js?
&lt;/h3&gt;

&lt;p&gt;Two reasons: SEO and developer experience.&lt;/p&gt;

&lt;p&gt;A subtitle downloader tool lives and dies by organic search traffic. Server-side rendering was non-negotiable. Next.js App Router gave me that plus React Server Components, which meant I could fetch data on the server without shipping unnecessary JavaScript to the client.&lt;/p&gt;

&lt;p&gt;The file-based routing also made it easy to create dozens of SEO landing pages without a complex routing setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why not use a third-party auth provider?
&lt;/h3&gt;

&lt;p&gt;Cost. As a solo developer bootstrapping with zero funding, every dollar matters. Auth0 and Clerk are great, but their free tiers have limits that would bite me as I scale. A simple JWT + Google OAuth flow took me a day to implement and costs nothing to run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified auth flow&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&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="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JWT_SECRET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;expiresIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;30d&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Is it as feature-rich as Auth0? No. Does it work perfectly for my use case? Yes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Hard Part: Subtitle Extraction at Scale
&lt;/h2&gt;

&lt;p&gt;The core technical challenge wasn't building the UI — it was reliably extracting subtitles from YouTube at scale.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 1: YouTube doesn't want you scraping subtitles
&lt;/h3&gt;

&lt;p&gt;YouTube's official Data API doesn't provide subtitle content. You can get video metadata, but not the actual transcript text. The &lt;code&gt;timedtext&lt;/code&gt; endpoint that serves subtitles to the YouTube player is undocumented and changes without notice.&lt;/p&gt;

&lt;p&gt;My approach: I reverse-engineered the subtitle delivery mechanism and built a resilient fetcher that handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Multiple subtitle tracks per video (manual + auto-generated)&lt;/li&gt;
&lt;li&gt;Language detection and selection&lt;/li&gt;
&lt;li&gt;Rate limiting with exponential backoff&lt;/li&gt;
&lt;li&gt;Graceful fallbacks when subtitles aren't available&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key insight was that YouTube serves subtitles as XML, which needs to be parsed and converted to standard formats:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// YouTube serves subtitles as XML like this:&lt;/span&gt;
&lt;span class="c1"&gt;// &amp;lt;text start="1.23" dur="4.5"&amp;gt;Hello world&amp;lt;/text&amp;gt;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;xmlToSrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xml&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&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;entries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parseXmlEntries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xml&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;entries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatTimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&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;end&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;formatTimestamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;i&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="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; --&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Challenge 2: Playlist expansion
&lt;/h3&gt;

&lt;p&gt;A YouTube playlist URL doesn't give you all the video IDs upfront. You need to paginate through the playlist API, which returns 50 items at a time. For a channel with 2,000+ videos, that's 40+ API calls just to get the video list.&lt;/p&gt;

&lt;p&gt;I built a streaming pipeline that starts checking subtitles as soon as the first batch of video IDs arrives, rather than waiting for the full list. This makes the UX feel much faster — users see progress immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  Challenge 3: Bulk downloads without killing the server
&lt;/h3&gt;

&lt;p&gt;When a user requests subtitles for 500 videos, you can't process them all synchronously. I implemented a queue-based system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;User submits playlist URL&lt;/li&gt;
&lt;li&gt;Server expands the playlist and returns video list&lt;/li&gt;
&lt;li&gt;Client requests subtitles in batches of 10&lt;/li&gt;
&lt;li&gt;Each batch is processed in parallel on the server&lt;/li&gt;
&lt;li&gt;Results are streamed back to the client&lt;/li&gt;
&lt;li&gt;Final ZIP is assembled client-side&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps server memory usage flat regardless of playlist size.&lt;/p&gt;




&lt;h2&gt;
  
  
  SEO: The Make-or-Break for Tool Sites
&lt;/h2&gt;

&lt;p&gt;For a free tool targeting organic traffic, SEO isn't a nice-to-have — it's the entire growth strategy. Here's what I did:&lt;/p&gt;

&lt;h3&gt;
  
  
  Programmatic SEO pages
&lt;/h3&gt;

&lt;p&gt;I created dedicated landing pages for different search intents:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;/youtube-subtitle-downloader&lt;/code&gt; — targets the generic search&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/bulk-youtube-subtitle-downloader&lt;/code&gt; — targets the bulk/power user search&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/what-is-an-srt-file&lt;/code&gt; — targets informational queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/guide/*&lt;/code&gt; — long-form content for long-tail keywords&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each page has unique content, structured data (JSON-LD), and proper meta tags. Next.js makes this straightforward with &lt;code&gt;generateMetadata&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateMetadata&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="p"&gt;}):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Metadata&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;params&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;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getTranslations&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;metadata&lt;/span&gt;&lt;span class="dl"&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;description&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;alternates&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;canonical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildCanonicalUrl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="na"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildCanonicalUrl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;buildCanonicalUrl&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Internationalization for traffic
&lt;/h3&gt;

&lt;p&gt;Adding support for Spanish, German, and Korean multiplied my addressable search volume by ~3x with relatively little effort. &lt;code&gt;next-intl&lt;/code&gt; handles the routing and message loading, and I used AI to help with translations (then had native speakers review them).&lt;/p&gt;

&lt;h3&gt;
  
  
  What I got wrong
&lt;/h3&gt;

&lt;p&gt;I initially created too many pages targeting similar keywords. Google got confused about which page to rank, and none of them ranked well. This is called "keyword cannibalization" — a lesson I learned the hard way. I'm now consolidating pages and using 301 redirects to focus authority.&lt;/p&gt;




&lt;h2&gt;
  
  
  Monetization: The Credits Model
&lt;/h2&gt;

&lt;p&gt;I went with a credits-based system instead of a traditional subscription:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free tier:&lt;/strong&gt; 5 credits per day (1 credit = 1 video subtitle download)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Daily reward:&lt;/strong&gt; +3 bonus credits for returning daily&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paid plans:&lt;/strong&gt; Credit packs via Stripe for heavy users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why credits instead of subscriptions? Two reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lower barrier to entry.&lt;/strong&gt; Users can try the tool without committing to a monthly fee. Most people only need subtitles occasionally.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Natural upsell.&lt;/strong&gt; When someone hits their limit mid-workflow, the friction of buying credits is much lower than subscribing. They're already invested in the task.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Stripe integration with Next.js was surprisingly smooth:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checkout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;line_items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;priceId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;quantity&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="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;success_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&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="s2"&gt;/pricing?success=true`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cancel_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&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="s2"&gt;/pricing?canceled=true`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;credits&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;creditAmount&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 webhook handles credit allocation after payment confirmation. Simple, reliable, no subscription management complexity.&lt;/p&gt;




&lt;h2&gt;
  
  
  Adding AI: The Unexpected Differentiator
&lt;/h2&gt;

&lt;p&gt;The original product was just a subtitle downloader. But I noticed users were downloading transcripts to feed them into ChatGPT for summaries. So I built it in.&lt;/p&gt;

&lt;p&gt;Now users can paste a YouTube URL and get:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AI-generated summary of the video&lt;/li&gt;
&lt;li&gt;Key points extraction&lt;/li&gt;
&lt;li&gt;A mind map of the content structure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I used DeepSeek's API for this — it's significantly cheaper than OpenAI for long-context tasks, and the quality is excellent for summarization. The cost per summary is roughly $0.002, which makes it viable even on the free tier.&lt;/p&gt;

&lt;p&gt;This feature turned out to be the biggest differentiator. There are dozens of YouTube subtitle downloaders, but very few that combine bulk extraction with AI analysis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lessons Learned After 3 Months
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What worked
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Solving my own problem.&lt;/strong&gt; I built this because I needed it. That meant I understood the user deeply from day one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Next.js + Vercel.&lt;/strong&gt; Zero DevOps overhead. I deploy with &lt;code&gt;git push&lt;/code&gt; and never think about servers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Credits model.&lt;/strong&gt; Lower friction than subscriptions for a tool that people use sporadically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internationalization early.&lt;/strong&gt; Adding i18n from the start was much easier than retrofitting it later.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start with fewer pages.&lt;/strong&gt; I created 30+ SEO pages before validating which keywords actually had traffic. Should have started with 3-5 and expanded based on data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build in public sooner.&lt;/strong&gt; I spent 2 months building in silence. Sharing progress on Twitter and dev communities from week 1 would have built an audience before launch.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Focus on backlinks from day one.&lt;/strong&gt; On-page SEO is necessary but not sufficient. Without quality backlinks, Google won't rank you no matter how good your content is.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Numbers (honest)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Monthly visitors:&lt;/strong&gt; ~600 (growing slowly)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paying users:&lt;/strong&gt; A handful&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Revenue:&lt;/strong&gt; Enough for coffee, not rent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time invested:&lt;/strong&gt; ~400 hours over 3 months&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Is it a success? Not yet. But it's a real product that real people use, and the foundation is solid. The growth curve for SEO-driven tools is slow at first and compounds over time. I'm playing the long game.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You're Building a Similar Tool
&lt;/h2&gt;

&lt;p&gt;A few tactical tips:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use Next.js App Router&lt;/strong&gt; if SEO matters. The metadata API and server components are a huge advantage over client-side frameworks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Don't over-engineer auth.&lt;/strong&gt; JWT + OAuth is enough for most indie projects. You can always migrate to a provider later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Ship the MVP in 2 weeks, then iterate.&lt;/strong&gt; My biggest regret is spending too long on features nobody asked for.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Track everything from day one.&lt;/strong&gt; Google Analytics + Search Console + Microsoft Clarity. You can't improve what you can't measure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Write content that helps people.&lt;/strong&gt; The best SEO strategy is genuinely useful content. Google is surprisingly good at detecting fluff.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;If you're working on a side project or building in public, I'd love to connect. Drop a comment about what you're building — I read every one.&lt;/p&gt;

&lt;p&gt;You can check out the tool at &lt;a href="https://ytvidhub.com/" rel="noopener noreferrer"&gt;ytvidhub.com&lt;/a&gt; if you ever need YouTube subtitles in bulk.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
