<?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: PlatinumJ</title>
    <description>The latest articles on DEV Community by PlatinumJ (@platinumj).</description>
    <link>https://dev.to/platinumj</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%2F4174847%2F50cb9856-3ba1-474f-ae51-65d716dc5edd.png</url>
      <title>DEV Community: PlatinumJ</title>
      <link>https://dev.to/platinumj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/platinumj"/>
    <language>en</language>
    <item>
      <title>I built 150 dev tools nobody asked for. Google sent me 6 clicks.</title>
      <dc:creator>PlatinumJ</dc:creator>
      <pubDate>Sat, 10 Oct 2026 08:40:46 +0000</pubDate>
      <link>https://dev.to/platinumj/i-built-150-dev-tools-nobody-asked-for-google-sent-me-6-clicks-5h0m</link>
      <guid>https://dev.to/platinumj/i-built-150-dev-tools-nobody-asked-for-google-sent-me-6-clicks-5h0m</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR (for the scrollers)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;I built &lt;a href="https://dauntexlabs.com" rel="noopener noreferrer"&gt;dauntexlabs&lt;/a&gt;: about 150 small tools (some still in progress, and yes, the plan is 500 someday lol). JSON stuff, hashing, PDF merge, image convert, aviation calculators, Indian legacy font converters. They all run &lt;strong&gt;entirely in your browser&lt;/strong&gt;. No backend. Your files are meant to stay on your laptop, and there are tests that check it.&lt;/li&gt;
&lt;li&gt;It's a fully static Next.js export. One HTML page per tool, shared JS kept around &lt;strong&gt;105 KB&lt;/strong&gt;, heavy libs only load when you click the button that needs them.&lt;/li&gt;
&lt;li&gt;"Privacy-first" is a claim everyone makes. So I made it a &lt;strong&gt;test&lt;/strong&gt;: a canary string goes into every tool, and the test fails if it shows up in any network request, URL, page title, storage or console.&lt;/li&gt;
&lt;li&gt;Three months of Search Console: &lt;strong&gt;20.8K impressions, 6 clicks, average position 76.&lt;/strong&gt; Google owns "km to miles". I'm not beating a widget.&lt;/li&gt;
&lt;li&gt;So I went niche on purpose: crosswind calculators for pilots, Krutidev to Unicode for Hindi typists, stuff with like 12 users each. Nobody needs it. Some people &lt;em&gt;really&lt;/em&gt; need it.&lt;/li&gt;
&lt;li&gt;Confession: it's mostly &lt;strong&gt;vibe coded&lt;/strong&gt; with Claude Code. What keeps it from being slop is a rules file, specs before code, and a test suite that acts as the reviewer. Code's public: &lt;a href="https://github.com/jha-adrs/dauntexlabs" rel="noopener noreferrer"&gt;github.com/jha-adrs/dauntexlabs&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole post. If you want the how, keep going.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why build this at all
&lt;/h2&gt;

&lt;p&gt;Ngl, there is no business here. Every tool on the site exists somewhere else already.&lt;/p&gt;

&lt;p&gt;What annoyed me was &lt;em&gt;how&lt;/em&gt; they exist. You want to merge two PDFs, and the top result wants you to upload your bank statement to some server, wait, then download it back. You want to decode a JWT, and you're pasting a production token into a random site with 14 trackers on it.&lt;/p&gt;

&lt;p&gt;None of that needs a server. Browsers can hash, encrypt, read PDFs and re-encode images. So the rule for the project was simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the tool can run in the browser, it runs in the browser. If it can't, it doesn't ship.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's the niche. It solves a problem most people don't have, and the ones who do usually don't know they have it. Very much a "good to have" project. I'm fine with that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup: static everything
&lt;/h2&gt;

&lt;p&gt;The stack is boring on purpose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15 with &lt;code&gt;output: 'export'&lt;/code&gt;.&lt;/strong&gt; Every route becomes a plain HTML file. I picked Next over a plain SPA only for SEO: each tool gets its own real page with its own title and description baked in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One registry file runs the whole site.&lt;/strong&gt; &lt;code&gt;lib/tools.ts&lt;/code&gt; is a list of tools (slug, name, category, blurb, keywords). The homepage, search, category filters, every tool page, &lt;code&gt;sitemap.xml&lt;/code&gt; and &lt;code&gt;robots.txt&lt;/code&gt; all come from that one list. Add an entry, and the page, card and sitemap row show up by themselves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Each tool is its own lazy chunk.&lt;/strong&gt; A &lt;code&gt;slug → dynamic(import(...))&lt;/code&gt; map means the PGP tool's code never loads on the word counter page.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// components/ToolMount.tsx (shape, trimmed)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TOOLS&lt;/span&gt; &lt;span class="o"&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;merge-pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/tools/MergePdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pgp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="nf"&gt;dynamic&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/tools/Pgp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="c1"&gt;// ...140-something more&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No server, no database, no auth. Deploy is "copy the &lt;code&gt;out/&lt;/code&gt; folder somewhere". It's giving 2009 and I love it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bundle budget
&lt;/h2&gt;

&lt;p&gt;When you have 150 tools (and you're delulu enough to aim for 500), the easy failure is that every page slowly ships every library. So there's a budget: &lt;strong&gt;shared first-load JS stays around 105 KB&lt;/strong&gt;, and it only grows about 1 KB per dozen new registry entries.&lt;/p&gt;

&lt;p&gt;Rules that keep it there:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use Web APIs before libraries.&lt;/strong&gt; SHA, HMAC and AES go through &lt;code&gt;crypto.subtle&lt;/code&gt;. Image tools use the native Canvas API with zero libs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write it yourself when the platform has a gap.&lt;/strong&gt; Web Crypto doesn't do MD5 (fair, MD5 is cooked). People still need it for checksums, so &lt;code&gt;lib/md5.ts&lt;/code&gt; is a hand-ported MD5. Small, no dependency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Three libraries are allowed, and they load inside the click handler.&lt;/strong&gt; &lt;code&gt;openpgp&lt;/code&gt;, &lt;code&gt;pdf-lib&lt;/code&gt; and &lt;code&gt;qrcode-generator&lt;/code&gt; are bundled (no CDN), and they're imported &lt;em&gt;inside&lt;/em&gt; the function that needs them. Not at the top of the file. Not on page load.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PDFDocument&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pdf-lib&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;// only now, only here&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;out&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;PDFDocument&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="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After every build I check the output to make sure those libs show up as their own per-tool chunks and not in the shared bundle. One stray top-level import and the budget is gone.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making "private" a test, not a vibe
&lt;/h2&gt;

&lt;p&gt;Every tool site says "we respect your privacy". Cool. Prove it.&lt;/p&gt;

&lt;p&gt;Here's what actually enforces it:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A static guard over the source.&lt;/strong&gt; A Vitest test scans the tool code for &lt;code&gt;fetch&lt;/code&gt;, XHR, WebSocket, &lt;code&gt;sendBeacon&lt;/code&gt;, storage writes, &lt;code&gt;console.*&lt;/code&gt; and history changes. If someone (me, at 1am) adds a network call to a tool, the test fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A canary string in the browser.&lt;/strong&gt; A Playwright test types a unique string like &lt;code&gt;CANARY-7f3a...&lt;/code&gt; into every tool that takes text or files. Then it checks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;every network request the page made&lt;/li&gt;
&lt;li&gt;the URL (path, query and hash)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;document.title&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;localStorage and sessionStorage&lt;/li&gt;
&lt;li&gt;the console&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the canary shows up anywhere, the test fails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. A test that tests the test.&lt;/strong&gt; This one's my favourite. The privacy spec includes a self-check that &lt;strong&gt;plants a leak on purpose&lt;/strong&gt; and asserts the canary check catches it. A privacy test that always passes is lowkey worse than no test, because it makes you feel safe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. CSP as the last wall.&lt;/strong&gt; &lt;code&gt;public/_headers&lt;/code&gt; sets a Content Security Policy that only allows connections to the site itself and analytics. So even if code slips through, the browser blocks the request. There's an e2e test that fires a cross-origin request and asserts it gets blocked.&lt;/p&gt;

&lt;p&gt;Small detail I'm weirdly proud of: search from inner pages goes to &lt;code&gt;/#q=term&lt;/code&gt;, not &lt;code&gt;/?q=term&lt;/code&gt;. The part after &lt;code&gt;#&lt;/code&gt; is never sent to the server, so your search doesn't land in anyone's access logs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The honest part
&lt;/h3&gt;

&lt;p&gt;The privacy page used to say "nothing ever leaves your device". I changed it to "designed to run on your device", plus a section on the circumstances where data &lt;em&gt;could&lt;/em&gt; leave your device.&lt;/p&gt;

&lt;p&gt;Why make it weaker? Because the absolute version isn't something I can promise. I control my code. I don't control your 9 Chrome extensions. Saying "designed to" plus tests that back it up is more honest than a guarantee I can't keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing tools that draw pixels
&lt;/h2&gt;

&lt;p&gt;About &lt;strong&gt;1,780 Vitest tests&lt;/strong&gt;, one suite per tool, rendering the real component and checking real output. The crypto ones do proper round trips: encrypt with AES or PGP, decrypt, get the plaintext back.&lt;/p&gt;

&lt;p&gt;Image tools were the problem. jsdom has no real canvas, so unit tests there can only check the &lt;em&gt;flow&lt;/em&gt; (file loads, button works, download fires). They can't tell you the JPEG is actually a JPEG.&lt;/p&gt;

&lt;p&gt;So Playwright handles those, in real Chromium, and checks the &lt;strong&gt;downloaded bytes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JPEG and WebP outputs start with the right magic numbers&lt;/li&gt;
&lt;li&gt;resized PNGs have the right width and height, read from the IHDR chunk&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;.ico&lt;/code&gt; file has the multi-size header&lt;/li&gt;
&lt;li&gt;QR codes get &lt;strong&gt;decoded back&lt;/strong&gt; with jsQR, and only the eye styles that actually scan are offered in the UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last one matters more than it sounds. Some fancy QR eye shapes look great and just don't decode. So the test decides which styles are allowed, not my taste.&lt;/p&gt;

&lt;h2&gt;
  
  
  Confession: it's vibe coded (with seatbelts)
&lt;/h2&gt;

&lt;p&gt;Most of this code was written by Claude Code, not typed by me. Not gonna pretend otherwise.&lt;/p&gt;

&lt;p&gt;The pace makes it obvious anyway. The repo is &lt;a href="https://github.com/jha-adrs/dauntexlabs" rel="noopener noreferrer"&gt;public&lt;/a&gt;, so you can check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;June 9:&lt;/strong&gt; first commit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;June 20:&lt;/strong&gt; 68 new tools in four commits. One day.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;October 7–8:&lt;/strong&gt; 59 commits in two days, for a full visual rebrand plus the niche expansion below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No way I hand-write 68 tools in a day. But "vibe code 150 tools" is also exactly how you get 150 slightly broken tools. So the vibes run inside some rails.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. A rules file the agent reads every session.&lt;/strong&gt; There's a &lt;code&gt;CLAUDE.md&lt;/code&gt; at the repo root. It's not "please write good code" energy. It's concrete stuff the agent can check itself against:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no &lt;code&gt;fetch&lt;/code&gt;, XHR or WebSocket in tool logic&lt;/li&gt;
&lt;li&gt;heavy libs get imported inside the handler, never at the top&lt;/li&gt;
&lt;li&gt;build every tool from the shared UI kit, don't invent new CSS classes&lt;/li&gt;
&lt;li&gt;a 5-step "adding a tool" checklist (registry entry, component, mount line, about/FAQ content, privacy canary case)&lt;/li&gt;
&lt;li&gt;shared JS stays around 105 KB&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time I correct the agent on something twice, it goes in that file. That file is basically the project's memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Spec before code for anything bigger than one tool.&lt;/strong&gt; The repo has 6 design specs and 3 implementation plans under &lt;code&gt;docs/superpowers/&lt;/code&gt;. The flow: the agent writes a spec, I push back on it, we agree, then a plan, then code. The niche expansion spec literally starts with my Search Console table. The data made the call, then the agent did the typing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Tests are the real code reviewer.&lt;/strong&gt; I can't line-by-line review 68 tools in a day, and honestly neither can you. So the 1,780 tests, the privacy canary and the CSP checks do that job. &lt;code&gt;npm run verify&lt;/code&gt; (typecheck, tests, build) runs as a pre-push hook, so red code doesn't leave my laptop.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. My job is deciding, not typing.&lt;/strong&gt; What to build. What &lt;em&gt;not&lt;/em&gt; to build: HEIC to JPG got cut because the decoder alone is over 1.3 MB, and OCR is out entirely. And rules like "a font map ships only if two independent sources agree". An AI will happily hand you a confident, plausible-looking character map. That rule exists so "looks right" never counts as "is right".&lt;/p&gt;

&lt;p&gt;So yeah, it's vibe coded. But the vibes have a test suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The numbers (it's not giving viral)
&lt;/h2&gt;

&lt;p&gt;Three months of Google Search Console:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Pages&lt;/th&gt;
&lt;th&gt;Impressions&lt;/th&gt;
&lt;th&gt;Clicks&lt;/th&gt;
&lt;th&gt;Avg position&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Unit converters (km to mi etc.)&lt;/td&gt;
&lt;td&gt;220&lt;/td&gt;
&lt;td&gt;16,791&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;78.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nautical / knots converters&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;td&gt;1,430&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;61.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tool pages&lt;/td&gt;
&lt;td&gt;82&lt;/td&gt;
&lt;td&gt;2,523&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;68.7&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;20.8K impressions. 6 clicks.&lt;/strong&gt; Average position 76, which is page 8. Nobody goes to page 8. Page 8 is where pages go to touch grass.&lt;/p&gt;

&lt;p&gt;The lesson took me a while to accept. Search "km to miles" and Google shows the answer in its own widget before any result. 16,791 people saw my page in results and 1 person clicked. I'm not out-ranking a calculator Google built into the search page, and I shouldn't try.&lt;/p&gt;

&lt;p&gt;But the few clicks I did get were all niche: knots and nautical miles, "query params to json", a JSON pivot tool. Weird long queries where page 1 is weak.&lt;/p&gt;

&lt;h2&gt;
  
  
  So I went more niche, on purpose
&lt;/h2&gt;

&lt;p&gt;The new rule: go after tools that are &lt;strong&gt;niche, usually paywalled or upload-only, and few people need&lt;/strong&gt;. Then make them free and on-device.&lt;/p&gt;

&lt;p&gt;What that looked like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;I &lt;code&gt;noindex&lt;/code&gt;ed 220 converter pages.&lt;/strong&gt; They still work, they're still linked, but they're out of the sitemap. They were burning crawl budget for 1 click.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aviation calculators:&lt;/strong&gt; crosswind component, wind correction angle, density altitude, flight time and fuel. Pilots and student pilots need these, and a lot of the existing ones are paywalled or clunky.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;India-specific tools:&lt;/strong&gt; a GSTIN validator, Indian number formats (lakh and crore), and legacy Hindi font converters like Krutidev to Unicode. A lot of government and older office documents in India are still typed in these old fonts, and converting them is painful.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real content on each page:&lt;/strong&gt; an about, how-to and FAQ block, server-rendered, with FAQ schema. A tool page with only a text box doesn't rank.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One rule I didn't bend: &lt;strong&gt;a legacy font converter ships only if its character map checks out against at least two independent sources and real text.&lt;/strong&gt; The Shivaji font map failed that check. So that page sits in "under maintenance" instead of shipping something that silently mangles someone's document. A wrong converter is worse than no converter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd tell past me
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pick the niche first, not after 150 tools.&lt;/strong&gt; I built breadth, then found out breadth doesn't rank. Should've started with "who's annoyed and underserved" and built 10 tools for them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If AI writes the code, you write the rails.&lt;/strong&gt; A rules file, specs and tests are what turn vibe coding into something you can actually ship.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If a claim matters, make it a test.&lt;/strong&gt; "Private", "fast", "small bundle" are all just vibes until something fails when they stop being true.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write down the boring rules.&lt;/strong&gt; "Libs load inside the handler." "Two sources or it doesn't ship." These are one-liners, and they're why the project didn't rot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search Console is humbling, open it early.&lt;/strong&gt; The numbers will tell you things your ego won't.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;More niche tools, real FAQ content on older pages, and I'll post the numbers again in a few months, good or bad. If the clicks go from 6 to 60, you'll hear about it. If they go to 7, you'll hear about that too.&lt;/p&gt;

&lt;p&gt;If you're a pilot, a Hindi typist, or someone who refuses to upload their PDFs to random servers, the site is &lt;a href="https://dauntexlabs.com" rel="noopener noreferrer"&gt;dauntexlabs.com&lt;/a&gt; and the code is on &lt;a href="https://github.com/jha-adrs/dauntexlabs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you have a niche tool you've always wanted on-device, drop it in the comments. Weirder is better.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>ai</category>
      <category>buildinpublic</category>
    </item>
  </channel>
</rss>
