<?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: chenghui wu</title>
    <description>The latest articles on DEV Community by chenghui wu (@chenghui_wu_1613965a032b1).</description>
    <link>https://dev.to/chenghui_wu_1613965a032b1</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%2F4036243%2F6a49ad95-7794-4bf0-98a3-f073476e8f0d.png</url>
      <title>DEV Community: chenghui wu</title>
      <link>https://dev.to/chenghui_wu_1613965a032b1</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chenghui_wu_1613965a032b1"/>
    <language>en</language>
    <item>
      <title>15 tiny developer annoyances I stopped tolerating this year (and the browser tools that fixed them)</title>
      <dc:creator>chenghui wu</dc:creator>
      <pubDate>Fri, 24 Jul 2026 02:56:17 +0000</pubDate>
      <link>https://dev.to/chenghui_wu_1613965a032b1/15-tiny-developer-annoyances-i-stopped-tolerating-this-year-and-the-browser-tools-that-fixed-them-3mf</link>
      <guid>https://dev.to/chenghui_wu_1613965a032b1/15-tiny-developer-annoyances-i-stopped-tolerating-this-year-and-the-browser-tools-that-fixed-them-3mf</guid>
      <description>&lt;p&gt;You know that specific flavor of dev annoyance — the tiny task that shouldn't exist, appears three times a week, and steals five minutes each time?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"This JWT looks wrong somehow."&lt;/li&gt;
&lt;li&gt;"The API returned 418. Cool. What?"&lt;/li&gt;
&lt;li&gt;"I need to strip EXIF before I post this photo."&lt;/li&gt;
&lt;li&gt;"Merge these 8 PDFs into one, please."&lt;/li&gt;
&lt;li&gt;"How much will this GPT-4o batch actually cost me?"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually, none of them are a crisis. Together, they're death by a thousand paper cuts. Over the last year I got tired of it and started building a tool for every single one — &lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;&lt;strong&gt;DevKits.vip&lt;/strong&gt;&lt;/a&gt;. It's now &lt;strong&gt;160+ tools&lt;/strong&gt;, everything runs locally in your browser, no accounts, no uploads.&lt;/p&gt;

&lt;p&gt;This post isn't the tool list. It's &lt;strong&gt;the 15 scenarios&lt;/strong&gt;. Every dev has hit at least half of these. Let's go.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ground rules
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;100% local.&lt;/strong&gt; Every operation runs in your browser. Your JWTs, private keys, PDFs, and photos never touch a server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No accounts, no tracking of your inputs.&lt;/strong&gt; Analytics counts page views. That's it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free forever.&lt;/strong&gt; No trial, no upgrade nag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're the kind of person who reflexively pastes secrets into random online tools, I hope this post at least gives you a safer place to do it.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Hero: three tools in one browser session — JWT Verifier, Fake Data Generator, Password Strength Checker"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  1. "A coworker sent me a JWT and something's off"
&lt;/h2&gt;

&lt;p&gt;The user says login is broken. You get the JWT. Now what?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Header wrong? Payload wrong? Signature wrong?&lt;/li&gt;
&lt;li&gt;Expired? Not-yet-valid? Issued in the future because someone's server clock is wild?&lt;/li&gt;
&lt;li&gt;The classic — &lt;code&gt;alg: "none"&lt;/code&gt; because someone's library trusted the header?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Old flow: paste into jwt.io, squint at the payload, wonder if the signature was actually checked, dig up the key from a Slack thread from 2 months ago.&lt;/p&gt;

&lt;p&gt;New flow: &lt;strong&gt;&lt;a href="https://devkits.vip/tools/jwt-decoder" rel="noopener noreferrer"&gt;JWT Decoder&lt;/a&gt;&lt;/strong&gt; shows the header + payload immediately. If you have the signing key (secret or public PEM/JWK), &lt;strong&gt;&lt;a href="https://devkits.vip/tools/jwt-verifier" rel="noopener noreferrer"&gt;JWT Verifier&lt;/a&gt;&lt;/strong&gt; takes it and gives you a definitive pass/fail — plus per-claim time status (&lt;code&gt;exp&lt;/code&gt;, &lt;code&gt;nbf&lt;/code&gt;, &lt;code&gt;iat&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;It handles all 12 RFC 7518 algorithms: &lt;code&gt;HS256/384/512&lt;/code&gt;, &lt;code&gt;RS256/384/512&lt;/code&gt;, &lt;code&gt;PS256/384/512&lt;/code&gt;, &lt;code&gt;ES256/384/512&lt;/code&gt;. &lt;code&gt;alg: none&lt;/code&gt; is explicitly rejected as invalid.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="JWT Verifier: green signature, red expired chip"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Companion tools when you're on the &lt;em&gt;producing&lt;/em&gt; side:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/jwt-generator" rel="noopener noreferrer"&gt;JWT Generator&lt;/a&gt;&lt;/strong&gt; — signs with any of the 12 algorithms&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/jwks-generator" rel="noopener noreferrer"&gt;JWKS Generator&lt;/a&gt;&lt;/strong&gt; — build a &lt;code&gt;/.well-known/jwks.json&lt;/code&gt; from your public keys&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/public-key-extractor" rel="noopener noreferrer"&gt;Public Key Extractor&lt;/a&gt;&lt;/strong&gt; — derive the public key from a private one (found out your JWKS is out of date? this is faster than regenerating)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. "Two API responses look almost identical, but which field actually changed?"
&lt;/h2&gt;

&lt;p&gt;You're regression-testing an API. Git-style diff shows you 40 red-green lines — but 39 of them are because your JSON library sorted keys differently.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-diff" rel="noopener noreferrer"&gt;JSON Diff&lt;/a&gt;&lt;/strong&gt; does a &lt;strong&gt;structural&lt;/strong&gt; comparison. Key order doesn't matter. It tells you: "field &lt;code&gt;user.email&lt;/code&gt; changed from &lt;code&gt;alice@a.com&lt;/code&gt; to &lt;code&gt;alice@b.com&lt;/code&gt;. Nothing else."&lt;/p&gt;

&lt;p&gt;Same idea for &lt;strong&gt;&lt;a href="https://devkits.vip/tools/yaml-diff" rel="noopener noreferrer"&gt;YAML Diff&lt;/a&gt;&lt;/strong&gt; (Kubernetes / Helm values), &lt;strong&gt;&lt;a href="https://devkits.vip/tools/xml-diff" rel="noopener noreferrer"&gt;XML Diff&lt;/a&gt;&lt;/strong&gt;, and character-level &lt;strong&gt;&lt;a href="https://devkits.vip/tools/text-diff" rel="noopener noreferrer"&gt;Text Diff&lt;/a&gt;&lt;/strong&gt; with syntax-highlighted &lt;strong&gt;&lt;a href="https://devkits.vip/tools/code-diff" rel="noopener noreferrer"&gt;Code Diff&lt;/a&gt;&lt;/strong&gt; for actual source code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus:&lt;/strong&gt; all 5 diff tools now generate &lt;strong&gt;shareable URLs&lt;/strong&gt;. Content is compressed with &lt;code&gt;deflate-raw&lt;/code&gt; into the URL hash — nothing sent to any server, but the link works cross-machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="JSON Diff: one real change, no key-order noise"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3. "Postman gave me a cURL. I need it in Go."
&lt;/h2&gt;

&lt;p&gt;Someone drops a &lt;code&gt;curl -X POST -H 'Authorization: Bearer …'&lt;/code&gt; in Slack. You need it as production code by end of day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/curl-converter" rel="noopener noreferrer"&gt;cURL Converter&lt;/a&gt;&lt;/strong&gt; — paste the cURL, click a language tab: &lt;strong&gt;Python / Node / Go / PHP / Ruby / Java&lt;/strong&gt;. Ready to compile. Handles multi-line curls, multiple headers, JSON bodies, basic auth, everything.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="cURL Converter: Stripe charge command → Go code"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. "The API returned 418. Cool. What?"
&lt;/h2&gt;

&lt;p&gt;You know 200, 404, 500. But 418? 451? 511? And the perennial code-review argument: &lt;strong&gt;401 vs 403&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/http-status-codes" rel="noopener noreferrer"&gt;HTTP Status Codes reference&lt;/a&gt;&lt;/strong&gt; — 60+ codes, each on its own page, with the RFC citation, "when to use it," "how clients react to it," and internal comparisons. The &lt;strong&gt;&lt;a href="https://devkits.vip/compare/301-vs-302-vs-307-vs-308" rel="noopener noreferrer"&gt;301/302/307/308 comparison&lt;/a&gt;&lt;/strong&gt; and the &lt;strong&gt;401 vs 403&lt;/strong&gt; breakdown are worth bookmarking alone.&lt;/p&gt;

&lt;p&gt;Same treatment for &lt;strong&gt;&lt;a href="https://devkits.vip/http-headers" rel="noopener noreferrer"&gt;HTTP Headers&lt;/a&gt;&lt;/strong&gt; (45 headers, real-world examples) and &lt;strong&gt;&lt;a href="https://devkits.vip/mime-types" rel="noopener noreferrer"&gt;MIME Types&lt;/a&gt;&lt;/strong&gt; (50+, one page each).&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="HTTP 401 vs 403: when to use each"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  5. "I need a regex for X. Not writing it from scratch."
&lt;/h2&gt;

&lt;p&gt;Every regex is a bug waiting to happen. The email one especially.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/regex-cookbook" rel="noopener noreferrer"&gt;Regex Cookbook&lt;/a&gt;&lt;/strong&gt; — 30 tested patterns (email, URL, IPv4, IPv6, UUID, hex color, phone, credit card, ISO date, semver, …) each with copy-ready JavaScript / Python / Go / Java snippets. &lt;strong&gt;These are tested.&lt;/strong&gt; You can steal them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/regex-tester" rel="noopener noreferrer"&gt;Regex Tester&lt;/a&gt;&lt;/strong&gt; — paste your pattern + test input, get live match highlighting and named-group output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/regex-replace" rel="noopener noreferrer"&gt;Regex Replace&lt;/a&gt;&lt;/strong&gt; — with backreferences and a live preview so you don't have to run your dry-run 12 times.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/visualize/regex" rel="noopener noreferrer"&gt;Visual Regex Explainer&lt;/a&gt;&lt;/strong&gt; — hover any part of a pattern to see what it does. Great for maintaining regex written by past-you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="Visual regex explainer: hover any part, see what it does"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. "My CSV has 47 columns and 'Smith, John' in one of them and I need it as JSON"
&lt;/h2&gt;

&lt;p&gt;The "convert this data blob before I can even do real work" tax. Every non-trivial CSV has quoted commas that break every naïve parser.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/csv-to-json" rel="noopener noreferrer"&gt;CSV → JSON&lt;/a&gt;&lt;/strong&gt; — proper RFC 4180 quoting&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-csv" rel="noopener noreferrer"&gt;JSON → CSV&lt;/a&gt;&lt;/strong&gt; — with the reverse escaping&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/yaml-to-json" rel="noopener noreferrer"&gt;YAML → JSON&lt;/a&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-yaml" rel="noopener noreferrer"&gt;JSON → YAML&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/xml-to-json" rel="noopener noreferrer"&gt;XML → JSON&lt;/a&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-xml" rel="noopener noreferrer"&gt;JSON → XML&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paste, click, done.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. "I have a JSON payload and I want a typed interface for it"
&lt;/h2&gt;

&lt;p&gt;Stripe webhook, Shopify order, whatever. You need &lt;code&gt;type Order = { … }&lt;/code&gt; and you'd rather not hand-write 47 field declarations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-typescript" rel="noopener noreferrer"&gt;JSON → TypeScript&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-go" rel="noopener noreferrer"&gt;JSON → Go structs&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-python" rel="noopener noreferrer"&gt;JSON → Python dataclasses&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-java" rel="noopener noreferrer"&gt;JSON → Java&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-csharp" rel="noopener noreferrer"&gt;C#&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-rust" rel="noopener noreferrer"&gt;Rust&lt;/a&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-to-php" rel="noopener noreferrer"&gt;PHP&lt;/a&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All handle nested objects, arrays, optional fields, &lt;code&gt;null&lt;/code&gt; unions, and preserve field naming casing.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="JSON → TypeScript interfaces, nested types handled"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  8. "The LLM returned broken JSON again"
&lt;/h2&gt;

&lt;p&gt;Every RAG / agent developer has hit this. The response comes wrapped in &lt;code&gt;&lt;/code&gt;`&lt;code&gt;json&lt;/code&gt;, contains trailing commas, uses &lt;code&gt;True&lt;/code&gt;/&lt;code&gt;False&lt;/code&gt;/&lt;code&gt;None&lt;/code&gt; because the model was trained on Python, single-quotes some fields. &lt;code&gt;JSON.parse()&lt;/code&gt; throws. You retry, which burns tokens.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-repair" rel="noopener noreferrer"&gt;JSON Repair&lt;/a&gt;&lt;/strong&gt; fixes all of the above, deterministically, in one pass. It handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trailing commas&lt;/li&gt;
&lt;li&gt;Single quotes instead of double&lt;/li&gt;
&lt;li&gt;Unquoted object keys&lt;/li&gt;
&lt;li&gt;Python-style &lt;code&gt;True&lt;/code&gt; / &lt;code&gt;False&lt;/code&gt; / &lt;code&gt;None&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Markdown code fences&lt;/li&gt;
&lt;li&gt;Missing closing brackets (best-effort recovery)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paste the broken output, get valid JSON.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="JSON Repair: LLM slop in, strict JSON out"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Related: &lt;strong&gt;&lt;a href="https://devkits.vip/tools/json-validator" rel="noopener noreferrer"&gt;JSON Validator&lt;/a&gt;&lt;/strong&gt; gives you the exact line/column of every syntax error if you'd rather fix by hand.&lt;/p&gt;




&lt;h2&gt;
  
  
  9. "Wait — does this photo I'm about to post leak my home address?"
&lt;/h2&gt;

&lt;p&gt;Every JPG straight off a phone can carry: GPS coordinates (to 5 meters), device serial number, timestamp, camera settings, sometimes even the WiFi network name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/exif-viewer" rel="noopener noreferrer"&gt;EXIF Viewer&lt;/a&gt;&lt;/strong&gt; — drag any photo, see what's in there. Includes a map pin if GPS is present.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/exif-remover" rel="noopener noreferrer"&gt;EXIF Remover&lt;/a&gt;&lt;/strong&gt; — strip all metadata losslessly (no re-encoding, no quality loss).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The file never leaves your browser. This is the one tool I'd tell a non-dev friend to use before posting anything to social media.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="EXIF Viewer: what your phone photo actually contains"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  10. "Client sent 8 PDFs. Needs to be one."
&lt;/h2&gt;

&lt;p&gt;The most-googled PDF task on Earth. And 90% of the "free" tools online want to upload your (probably confidential) client documents to their server.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/merge-pdf" rel="noopener noreferrer"&gt;Merge PDF&lt;/a&gt;&lt;/strong&gt; — drag, reorder, merge. Nothing uploaded.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/split-pdf" rel="noopener noreferrer"&gt;Split PDF&lt;/a&gt;&lt;/strong&gt; — range, chunks, or one file per page&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/remove-pdf-pages" rel="noopener noreferrer"&gt;Remove PDF Pages&lt;/a&gt;&lt;/strong&gt; — with "1, 3-5, last" syntax&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/rotate-pdf" rel="noopener noreferrer"&gt;Rotate PDF&lt;/a&gt;&lt;/strong&gt; — whole doc or range&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/pdf-text-extractor" rel="noopener noreferrer"&gt;PDF Text Extractor&lt;/a&gt;&lt;/strong&gt; — proper CJK support (many extractors mangle Chinese/Japanese/Korean)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="Merge PDF: drag to reorder, everything stays local"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  11. "I need a favicon set for a new project"
&lt;/h2&gt;

&lt;p&gt;12 sizes, a &lt;code&gt;manifest.webmanifest&lt;/code&gt;, and the HTML snippet. Every time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/favicon-generator" rel="noopener noreferrer"&gt;Favicon Generator&lt;/a&gt;&lt;/strong&gt; — drop one square image, get a ZIP with every size (16 / 32 / 180 / 192 / 512 / …), the manifest, and the exact &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; HTML to paste into &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/svg-optimizer" rel="noopener noreferrer"&gt;SVG Optimizer&lt;/a&gt;&lt;/strong&gt; — run your logo through SVGO in your browser before you rasterize it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/png-to-ico" rel="noopener noreferrer"&gt;PNG → ICO&lt;/a&gt;&lt;/strong&gt; — the "just the .ico please" case.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  12. "Cron expression &lt;code&gt;*/15 9-17 * * 1-5&lt;/code&gt; — when does that fire next?"
&lt;/h2&gt;

&lt;p&gt;Cron syntax reads like APL. And you always, always want to see the next 5 fire times before pushing.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/cron-parser" rel="noopener noreferrer"&gt;Cron Parser&lt;/a&gt;&lt;/strong&gt; — paste any expression, get plain English + the next N runs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/cron-generator" rel="noopener noreferrer"&gt;Cron Generator&lt;/a&gt;&lt;/strong&gt; — visual builder if you'd rather not type&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="Cron Parser: expression, English, next 5 runs"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  13. "Standup at 3pm JST. I'm in São Paulo. When?"
&lt;/h2&gt;

&lt;p&gt;Distributed teams. DST edge cases silently ruin calendar invites twice a year.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/timezone-converter" rel="noopener noreferrer"&gt;Timezone Converter&lt;/a&gt;&lt;/strong&gt; — DST-aware, any IANA zone, multi-column display&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/timestamp-converter" rel="noopener noreferrer"&gt;Timestamp Converter&lt;/a&gt;&lt;/strong&gt; — Unix epoch ↔ human, in every format ever&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/iso8601-duration" rel="noopener noreferrer"&gt;ISO 8601 Duration parser&lt;/a&gt;&lt;/strong&gt; — for parsing &lt;code&gt;PT2H30M&lt;/code&gt; out of an API response&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  14. "How much will this GPT-4o batch job actually cost me?"
&lt;/h2&gt;

&lt;p&gt;Blind estimate = surprise invoice. Vendor pricing pages are painful to compare.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/token-counter" rel="noopener noreferrer"&gt;Token Counter&lt;/a&gt;&lt;/strong&gt; — estimates for GPT-3.5/4/4o, Claude, Gemini&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/ai-cost-calculator" rel="noopener noreferrer"&gt;AI Cost Calculator&lt;/a&gt;&lt;/strong&gt; — 20+ models, &lt;strong&gt;daily-refreshed pricing&lt;/strong&gt; via a cron, side-by-side comparison, cache / batch / prompt-caching discounts factored in&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/text-chunker" rel="noopener noreferrer"&gt;Text Chunker&lt;/a&gt;&lt;/strong&gt; — character / word / token-based splits for RAG, shows per-chunk token counts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/cosine-similarity" rel="noopener noreferrer"&gt;Cosine Similarity&lt;/a&gt;&lt;/strong&gt; — pair mode + N×N matrix; useful for debugging why your RAG returned the wrong chunk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="AI Cost Calculator: same workload, wildly different bills"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  15. "How strong is my password, really?"
&lt;/h2&gt;

&lt;p&gt;Not "it has an uppercase letter and a number" strong — actually strong. Under a real attacker's compute budget.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://devkits.vip/tools/password-strength-checker" rel="noopener noreferrer"&gt;Password Strength Checker&lt;/a&gt;&lt;/strong&gt; gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entropy in bits&lt;/strong&gt; (the actual math, not a color bar)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Crack time under 4 attack models&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Online, throttled (login form with rate limits): 100 tries/sec&lt;/li&gt;
&lt;li&gt;Online, unthrottled (broken rate limit): 10k tries/sec&lt;/li&gt;
&lt;li&gt;Offline, GPU on a fast hash: 10 billion tries/sec&lt;/li&gt;
&lt;li&gt;Offline, GPU on bcrypt: 10k tries/sec&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Structural findings&lt;/strong&gt;: dictionary words, keyboard sequences (&lt;code&gt;qwerty&lt;/code&gt;, &lt;code&gt;1234&lt;/code&gt;), repeats, common patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional HIBP k-anonymity lookup&lt;/strong&gt; — checks Have I Been Pwned without ever sending your password. Only the first 5 chars of a SHA-1 hash go over the wire.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fun exercise: try &lt;code&gt;Summer2024!&lt;/code&gt;, &lt;code&gt;correct horse battery staple&lt;/code&gt;, and a 32-char random string. The gap between them is educational.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="Password Strength: "&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Related for the "I need a secret NOW" case:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/password-generator" rel="noopener noreferrer"&gt;Password Generator&lt;/a&gt;&lt;/strong&gt; — customizable alphabet, target entropy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/uuid-v7-generator" rel="noopener noreferrer"&gt;UUID v7 Generator&lt;/a&gt;&lt;/strong&gt; — time-ordered UUIDs for DB primary keys (RFC 9562)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://devkits.vip/tools/rsa-key-generator" rel="noopener noreferrer"&gt;RSA Key Pair Generator&lt;/a&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;a href="https://devkits.vip/tools/ecdsa-key-generator" rel="noopener noreferrer"&gt;ECDSA Key Pair Generator&lt;/a&gt;&lt;/strong&gt; — full PEM / JWK / DER output for JWT signing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Bonus: everything is discussable
&lt;/h2&gt;

&lt;p&gt;Every tool page has an in-page &lt;strong&gt;Comments&lt;/strong&gt; button in its hero — expandable thread pinned to that tool. There's also a &lt;strong&gt;&lt;a href="https://devkits.vip/messages" rel="noopener noreferrer"&gt;global Community Board&lt;/a&gt;&lt;/strong&gt; across all tools.&lt;/p&gt;

&lt;p&gt;No signup. Nickname auto-suggests from your rough geo (with your IP masked). Report / mod tools exist for spam.&lt;/p&gt;

&lt;p&gt;&lt;a href="/api/placeholder" class="article-body-image-wrapper"&gt;&lt;img src="/api/placeholder" alt="Community Board — no signup, chat by tool"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What's the catch?
&lt;/h2&gt;

&lt;p&gt;Honestly, none. It's a static Next.js site on Vercel. Cost to run: less than one coffee a month. There's no VC, no upsell, no email capture. I built it for me and it turned out other devs wanted it too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you find it useful:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bookmark &lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;devkits.vip&lt;/a&gt; — it's a fast keyboard target when you need "that one converter"&lt;/li&gt;
&lt;li&gt;Star / follow if I ever ship a GitHub repo (thinking about it)&lt;/li&gt;
&lt;li&gt;Subscribe to the &lt;strong&gt;&lt;a href="https://devkits.vip/changelog/feed.xml" rel="noopener noreferrer"&gt;RSS feed&lt;/a&gt;&lt;/strong&gt; for new releases (we ship weekly)&lt;/li&gt;
&lt;li&gt;Something missing? &lt;a href="https://devkits.vip/messages" rel="noopener noreferrer"&gt;Ping me on the community board.&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tech stack (for the curious)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15 App Router&lt;/strong&gt; + &lt;strong&gt;React 19&lt;/strong&gt; + &lt;strong&gt;Tailwind 3&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All crypto&lt;/strong&gt; via the browser's built-in Web Crypto API — no &lt;code&gt;crypto-js&lt;/code&gt;, no &lt;code&gt;jose&lt;/code&gt;, no &lt;code&gt;node-forge&lt;/code&gt;. Everything is native &lt;code&gt;subtle.generateKey&lt;/code&gt;, &lt;code&gt;subtle.sign&lt;/code&gt;, &lt;code&gt;subtle.verify&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDFs&lt;/strong&gt; via &lt;code&gt;pdf-lib&lt;/code&gt; (write) + &lt;code&gt;pdfjs-dist&lt;/code&gt; (read), including a hack to make text extraction work correctly on CJK PDFs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regex visualizer&lt;/strong&gt; built from scratch (parsing the pattern into an AST, no external lib)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diff algorithm&lt;/strong&gt; custom — Myers diff for text, structural walk for JSON/YAML/XML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero server-side data processing.&lt;/strong&gt; The comment board is the only thing that hits a DB (Neon Postgres, and it only ever stores comment content — never your tool inputs).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel&lt;/strong&gt; for hosting; a daily cron submits the sitemap to IndexNow so Bing / Yandex see new tools within a day&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Questions I get
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;"Why not use crypto-js / jose / node-forge?"&lt;/strong&gt;&lt;br&gt;
Every one of those is 100-400 KB gzipped. The browser has all of it built in, at zero bundle cost, running native code. There's no reason to ship a library that reimplements what your runtime already does — unless you need something the platform genuinely lacks (like RFC 6979 deterministic ECDSA, which we don't).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How do you make money?"&lt;/strong&gt;&lt;br&gt;
I don't, yet. It costs less than a coffee to run. If it ever becomes expensive I'll add non-tracking ads or open sponsorships. &lt;strong&gt;No auth wall, no premium tier. Ever.&lt;/strong&gt; The whole point is that these tools should exist without a login form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Is the source open?"&lt;/strong&gt;&lt;br&gt;
Not right now. I'm considering it. The concern is duplicate content — GitHub repos with heavy READMEs sometimes outrank their own product sites, which would be a weird outcome. I might open just the tool implementations without the marketing pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Can I self-host?"&lt;/strong&gt;&lt;br&gt;
Not currently, but it's a plain Next.js app with no backend beyond a Postgres comments table — nothing exotic. If enough people ask, I'll write a self-host guide.&lt;/p&gt;




&lt;p&gt;If you got this far, a share means a lot. Which of these annoyances did you last hit? Drop it in the comments — I'll add tools for the ones I don't cover yet.&lt;/p&gt;

&lt;p&gt;— &lt;em&gt;Built and maintained by one person, publicly, in a browser. If you're building something similar, &lt;a href="https://devkits.vip/messages" rel="noopener noreferrer"&gt;I'd love to see it&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I built 162 dev tools that never upload your data. Here's what I learned</title>
      <dc:creator>chenghui wu</dc:creator>
      <pubDate>Wed, 22 Jul 2026 07:15:18 +0000</pubDate>
      <link>https://dev.to/chenghui_wu_1613965a032b1/i-built-162-dev-tools-that-never-upload-your-data-heres-what-i-learned-b88</link>
      <guid>https://dev.to/chenghui_wu_1613965a032b1/i-built-162-dev-tools-that-never-upload-your-data-heres-what-i-learned-b88</guid>
      <description>&lt;h2&gt;
  
  
  The problem with 90% of "online dev tools"
&lt;/h2&gt;

&lt;p&gt;You paste a JWT into a random site to decode it. You paste JSON into another one to format it. You paste a private key into a third to extract the public half.&lt;/p&gt;

&lt;p&gt;Every one of those pastes is a leak. Your token, your JSON, your key — they hit someone else's server, get logged, and sometimes get sold.&lt;/p&gt;

&lt;p&gt;For sensitive stuff, most of us just skip online tools and open a REPL. But you don't want to &lt;code&gt;python -c "import base64; ..."&lt;/code&gt; for the 40th time this week either.&lt;/p&gt;

&lt;p&gt;I got tired of the tradeoff. So I built &lt;strong&gt;&lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;devkits.vip&lt;/a&gt;&lt;/strong&gt; — a set of &lt;strong&gt;162 developer tools&lt;/strong&gt;, all running &lt;strong&gt;entirely in the browser&lt;/strong&gt;. Nothing is uploaded. No crypto-js dependency. No jsrsasign. No node-forge. Just the browser's native Web Crypto API doing the heavy lifting.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The whole point&lt;/strong&gt;: &lt;code&gt;curl -sD - https://devkits.vip/tools/jwt-verifier &amp;gt; /dev/null&lt;/code&gt; followed by network-panel-verification shows &lt;em&gt;zero&lt;/em&gt; outbound requests when you actually use it. Try it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Homepage of devkits.vip showing hero and category grid"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The numbers
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Total tools&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;162&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Categories&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;11&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Interactive visualizers&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reference pages (MIME / HTTP / regex / ASCII / status codes …)&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~495&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data uploaded during typical use&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0 bytes&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses of &lt;code&gt;crypto-js&lt;/code&gt; / &lt;code&gt;jsrsasign&lt;/code&gt; / &lt;code&gt;node-forge&lt;/code&gt; in package.json&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JWT algorithms supported&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;12&lt;/strong&gt; (HS/RS/PS/ES × 256/384/512)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PBKDF2 iterations for AES&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;200,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last point is the whole thesis: everything is done with the browser's own primitives. If your browser can't do it, we don't ship it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Five things that ended up being interesting to build
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. A JWT tool that supports every algorithm in RFC 7518
&lt;/h3&gt;

&lt;p&gt;Most "JWT decoder" sites just base64-decode and hand-wave the signature. We do the actual verification, for the entire RFC 7518 algorithm family:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HS256 / HS384 / HS512&lt;/strong&gt; — HMAC with a shared secret&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RS256 / RS384 / RS512&lt;/strong&gt; — RSASSA-PKCS1-v1_5 with an RSA public key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PS256 / PS384 / PS512&lt;/strong&gt; — RSA-PSS (modern padding) with an RSA public key&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ES256 / ES384 / ES512&lt;/strong&gt; — ECDSA with a P-256, P-384, or P-521 public key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Paste a JWT and a public key (PEM or JWK), and you get a real signature check. The tool also flags time claims (&lt;code&gt;exp&lt;/code&gt; / &lt;code&gt;nbf&lt;/code&gt; / &lt;code&gt;iat&lt;/code&gt;) and explicitly rejects &lt;code&gt;alg: "none"&lt;/code&gt; — that classic JWT vulnerability where an attacker strips the signature and hopes the verifier accepts it.&lt;/p&gt;

&lt;p&gt;All twelve algorithms are wired straight into &lt;code&gt;crypto.subtle.sign&lt;/code&gt; / &lt;code&gt;crypto.subtle.verify&lt;/code&gt;. Zero JWT libraries in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="JWT Verifier showing signature check + time claim status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. RSA &amp;amp; ECDSA key generation, without a single crypto library
&lt;/h3&gt;

&lt;p&gt;The whole &lt;code&gt;asymmetric-keys.ts&lt;/code&gt; module is 150 lines. It generates a key pair via &lt;code&gt;crypto.subtle.generateKey&lt;/code&gt;, exports the private key as PKCS#8, the public key as SPKI, and both as JWK — all through browser APIs.&lt;/p&gt;

&lt;p&gt;Output formats I actually needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PEM&lt;/strong&gt; (PKCS#8 for private, SPKI for public) — for OpenSSL, Node, Go, Java, Python &lt;code&gt;cryptography&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JWK&lt;/strong&gt; — for JWT libraries, browser Web Crypto import, JWKS endpoints&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DER&lt;/strong&gt; — hex or base64, for low-level inspection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also a companion "&lt;strong&gt;Public Key Extractor&lt;/strong&gt;": paste a private key, get the matching public key. Useful when you inherit a &lt;code&gt;.pem&lt;/code&gt; file with no matching &lt;code&gt;.pub&lt;/code&gt;, or when you're about to publish a JWKS endpoint and only have the signing key on hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="RSA Key Generator showing private + public keys in PEM"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Regex Visualizer — the tool I wish I had in college
&lt;/h3&gt;

&lt;p&gt;Regex is dense. When someone shows me &lt;code&gt;^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$&lt;/code&gt; I want to see it &lt;em&gt;decomposed&lt;/em&gt;, not stare at a wall of characters.&lt;/p&gt;

&lt;p&gt;The Regex Visualizer at &lt;code&gt;/visualize/regex&lt;/code&gt; breaks any pattern into colored tokens with plain-English explanations, and shows live match highlighting against your test string. It's less "tool," more "textbook you can play with."&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Regex Visualizer showing token breakdown + live match"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. A fake-data generator that ships as ~5KB of word lists
&lt;/h3&gt;

&lt;p&gt;Every dev needs &lt;code&gt;10 fake users as CSV&lt;/code&gt; at some point. The usual workflow is &lt;code&gt;npm install faker&lt;/code&gt;, write a script, run it, delete. That's fine — but if you've already got a browser tab open, an online generator wins.&lt;/p&gt;

&lt;p&gt;The problem: most online generators are backend calls (privacy leak) or bundle &lt;code&gt;faker.js&lt;/code&gt; (~500KB gzipped).&lt;/p&gt;

&lt;p&gt;I inlined &lt;strong&gt;~50 items per category&lt;/strong&gt; as plain string arrays. Total: &lt;strong&gt;about 5KB&lt;/strong&gt;. That's enough entropy to look real for 100 rows of users. Combined with a &lt;strong&gt;seeded PRNG&lt;/strong&gt; (&lt;code&gt;mulberry32&lt;/code&gt;), you get reproducible output — same seed = same rows, byte for byte.&lt;/p&gt;

&lt;p&gt;25+ field types, 5 output formats:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON array&lt;/li&gt;
&lt;li&gt;JSONL / JSON Lines&lt;/li&gt;
&lt;li&gt;CSV (proper quoting for commas &amp;amp; newlines)&lt;/li&gt;
&lt;li&gt;SQL INSERT statements with configurable table name&lt;/li&gt;
&lt;li&gt;TypeScript &lt;code&gt;type Row = { ... }&lt;/code&gt; + a typed array literal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Fake Data Generator with SQL INSERT output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Password strength check that never uploads the password
&lt;/h3&gt;

&lt;p&gt;Every "how strong is my password" site is a security joke: you paste your actual password into their form. Even if they don't log it, they &lt;em&gt;could&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We do the entropy math locally — character-class analysis, keyboard-sequence detection, repeated-pattern detection, dictionary check — and estimate crack time under &lt;strong&gt;four realistic attack scenarios&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Online, throttled (10 tries/sec)&lt;/li&gt;
&lt;li&gt;Online, no throttling (100 tries/sec)&lt;/li&gt;
&lt;li&gt;Offline fast hash — GPU cluster on SHA-1 (10 billion tries/sec)&lt;/li&gt;
&lt;li&gt;Offline slow hash — bcrypt cost 10 (10k tries/sec)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There's also an &lt;strong&gt;optional&lt;/strong&gt; breach check against Have I Been Pwned, using their &lt;strong&gt;k-anonymity API&lt;/strong&gt;. Only the first 5 hex characters of the SHA-1 hash are sent (matches ~450 hashes on average). Your actual password never touches the network, even for the breach lookup.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Password Strength Checker showing crack-time table"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The rest of the toolkit (in ~10 seconds)
&lt;/h2&gt;

&lt;p&gt;Rather than list all 162, here's the vibe per category:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON (12)&lt;/strong&gt; — formatter, diff, repair (fixes LLM output — trailing commas, unquoted keys, python-style True/False), JSONPath tester, schema generator (Draft 2020-12 + OpenAI function-calling + Anthropic tool_use schemas), to-TS / to-Go / to-Rust / to-Python / to-C# / to-PHP / to-Java, flatten, minifier, escape, validator, sort, XML↔JSON, YAML↔JSON, CSV↔JSON&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encoding (9)&lt;/strong&gt; — base64 / base32 / base58 (Bitcoin + Solana + IPFS CID v0) / URL / HTML / hex / punycode / rot13 / unicode escape&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security (20)&lt;/strong&gt; — everything above + AES (GCM/CBC, 128/192/256, PBKDF2 200k iterations, self-describing ciphertext), bcrypt, HMAC, hash generator (MD5/SHA-1/SHA-256/SHA-512 with streaming for multi-GB files), JWKS generator (RFC 7517, auto SHA-256 thumbprint kid per RFC 7638)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI &amp;amp; LLM (4)&lt;/strong&gt; — cost calculator (&lt;strong&gt;live pricing&lt;/strong&gt; for GPT / Claude / Gemini / DeepSeek — refreshed daily by cron), token counter, RAG text chunker (recursive / paragraph / sentence / fixed strategies), cosine similarity (pair mode + N×N matrix)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Converters (21)&lt;/strong&gt; — cURL to Python/Node/Go/PHP/Java, number bases (BigInt-backed), unit converters (data size, bandwidth, Bitcoin, Ethereum, dates)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web (17)&lt;/strong&gt; — CIDR calculator, CSS visual generators (Grid, Flexbox, Box Shadow, Border Radius, cubic-bezier, text-shadow, glassmorphism, gradient), regex tester + replace, user-agent parser, meta tag preview (Google + Facebook + Twitter + LinkedIn cards), QR generator + reader&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF (10)&lt;/strong&gt; — extract text (with &lt;strong&gt;CJK support&lt;/strong&gt; — proper cmaps + geometric reading order, not pdf.js's hasEOL guesswork), merge, split, remove pages, rotate, password remover, metadata viewer, images↔PDF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image (19)&lt;/strong&gt; — compressor (with target-KB binary-search mode — kills the "just under 2MB please" pain), EXIF viewer + lossless remover, format converters, resizer, cropper, favicon generator (one image → full ZIP with .ico + PNGs + apple-touch + manifest + HTML snippet), SVG optimizer (full SVGO in browser), image diff (pixelmatch)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text (28)&lt;/strong&gt; — diff (with syntax highlighting for 14 languages, zero external highlight libs — I wrote a 150-line tokenizer), case converter, sort, dedup, word/char/line counter, markdown-to-HTML with the works&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generators (14)&lt;/strong&gt; — password, UUID v4 + v7, NanoID, ULID, KSUID, CUID2, Snowflake ID, fake data, lorem, random number / string / picker / shuffler&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time &amp;amp; Date (8)&lt;/strong&gt; — timestamp converter, timezone converter with DST, cron generator + parser, age calculator, date diff, working days with holiday support, ISO 8601 duration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="AI Cost Calculator comparing GPT / Claude / Gemini"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="CSS Grid Generator showing preview + CSS + Tailwind output"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The 495 reference pages nobody asked for (but Google loves)
&lt;/h2&gt;

&lt;p&gt;Some of my favorite dev-time browser habits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"quick, what's the MIME type for &lt;code&gt;.mjs&lt;/code&gt;?"&lt;/li&gt;
&lt;li&gt;"what does HTTP &lt;code&gt;Strict-Transport-Security&lt;/code&gt; actually do?"&lt;/li&gt;
&lt;li&gt;"give me a regex that matches an ISO 8601 date"&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The answer to each is &lt;code&gt;curl&lt;/code&gt; or Wikipedia away, but that's 3 tabs and 20 seconds. I inlined all of it as static pages, one URL per entity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;51 MIME type pages&lt;/strong&gt; at &lt;code&gt;/mime-types/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;46 HTTP status code pages&lt;/strong&gt; at &lt;code&gt;/tools/http-status-codes/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;48 HTTP header pages&lt;/strong&gt; at &lt;code&gt;/http-headers/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;30 regex cookbook patterns&lt;/strong&gt; at &lt;code&gt;/regex-cookbook/*&lt;/code&gt; — each with runnable JS, Python, Go, and Java snippets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;256 ASCII/Latin-1 character pages&lt;/strong&gt; at &lt;code&gt;/ascii/*&lt;/code&gt; — every character 0–255 gets its own page with hex, binary, HTML entity, URL encoding, and UTF-8 bytes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;22 seasonal "days until X" pages&lt;/strong&gt; at &lt;code&gt;/tools/days-until/*&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They're all static-rendered at build time by Next.js and served from the edge. This started as an SEO experiment but it also became my personal quick-reference — I use &lt;code&gt;/http-headers/strict-transport-security&lt;/code&gt; more than the MDN version because it's faster.&lt;/p&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="MIME types reference hub"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The tech stack
&lt;/h2&gt;

&lt;p&gt;Deliberately boring. Nothing to justify.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15.1.6&lt;/strong&gt; on the App Router&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;React 19&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript 5.7&lt;/strong&gt; in strict mode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tailwind CSS 3.4&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Deployed on &lt;strong&gt;Vercel&lt;/strong&gt; (SSG + edge CDN + analytics + speed insights)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Neon Postgres&lt;/strong&gt; — used &lt;em&gt;only&lt;/em&gt; for the comment board (&lt;code&gt;/messages&lt;/code&gt;), because that one thing does need persistence. Every other tool is 100% client-side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Crypto API&lt;/strong&gt; for all crypto — JWT signing, AES, RSA, ECDSA, HMAC, hashing, PBKDF2. No &lt;code&gt;crypto-js&lt;/code&gt;, no &lt;code&gt;jsrsasign&lt;/code&gt;, no &lt;code&gt;node-forge&lt;/code&gt;. Not a single crypto package in &lt;code&gt;package.json&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pdf-lib&lt;/code&gt; + &lt;code&gt;pdfjs-dist&lt;/code&gt;&lt;/strong&gt; for PDF read/write&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Canvas API + &lt;code&gt;exifr&lt;/code&gt; + &lt;code&gt;piexifjs&lt;/code&gt; + &lt;code&gt;pixelmatch&lt;/code&gt; + &lt;code&gt;svgo&lt;/code&gt; + &lt;code&gt;jsqr&lt;/code&gt; + &lt;code&gt;qrcode&lt;/code&gt;&lt;/strong&gt; for imaging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Static-rendered pages share ~103 KB of JS. Every tool page loads its heavy deps (svgo, pdf-lib, pdfjs, jszip, exifr, pixelmatch) via &lt;code&gt;await import()&lt;/code&gt; inside the operation handler, not at module top — so opening the JSON formatter doesn't pull down PDF rendering code.&lt;/p&gt;




&lt;h2&gt;
  
  
  How it grew: 16 releases in a few weeks
&lt;/h2&gt;

&lt;p&gt;The project is open in the sense that every release is public and documented. There's a &lt;strong&gt;&lt;a href="https://devkits.vip/changelog" rel="noopener noreferrer"&gt;Changelog&lt;/a&gt;&lt;/strong&gt; with 16 releases so far, and an &lt;strong&gt;&lt;a href="https://devkits.vip/changelog/feed.xml" rel="noopener noreferrer"&gt;RSS feed&lt;/a&gt;&lt;/strong&gt; if you want the drip.&lt;/p&gt;

&lt;p&gt;Recent shipments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image toolkit&lt;/strong&gt; — 19 privacy-first image tools in one drop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PDF toolkit&lt;/strong&gt; — 8 tools with CJK support, geometric reading order (not pdf.js's line-based guessing)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security wave&lt;/strong&gt; — RSA + ECDSA key generators, encrypt/decrypt, sign/verify, JWKS, public-key extractor, JWT verifier — all Web Crypto, no libraries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI toolkit&lt;/strong&gt; — cost calculator with live pricing, token counter, RAG chunker, cosine similarity&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS layout wave&lt;/strong&gt; — Flexbox + Grid + Box Shadow + Border Radius + cubic-bezier + text-shadow + glassmorphism generators, all with Tailwind output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="" class="article-body-image-wrapper"&gt;&lt;img alt="Changelog with recent releases"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Site&lt;/strong&gt;: &lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;devkits.vip&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any tool page&lt;/strong&gt; has a comment box at the bottom for feedback / bug reports&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feature requests&lt;/strong&gt;: &lt;a href="https://devkits.vip/messages" rel="noopener noreferrer"&gt;community board&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'd genuinely love to know what your paste-into-random-site-anyway workflow is — that's the next tool I want to build.&lt;/p&gt;

&lt;p&gt;If you want to hear about new tools, subscribe to the changelog RSS: &lt;code&gt;https://devkits.vip/changelog/feed.xml&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cover image is auto-generated by the site's &lt;code&gt;/api/og&lt;/code&gt; endpoint. All screenshots in this post are real screenshots of the live site — no mockups.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>privacy</category>
      <category>security</category>
      <category>tools</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built 31 developer tools in a weekend — here's what I learned</title>
      <dc:creator>chenghui wu</dc:creator>
      <pubDate>Sun, 19 Jul 2026 08:08:27 +0000</pubDate>
      <link>https://dev.to/chenghui_wu_1613965a032b1/i-built-31-developer-tools-in-a-weekend-heres-what-i-learned-1f3h</link>
      <guid>https://dev.to/chenghui_wu_1613965a032b1/i-built-31-developer-tools-in-a-weekend-heres-what-i-learned-1f3h</guid>
      <description>&lt;p&gt;Every time I want to format a JSON blob, decode a JWT, or convert a Unix timestamp, I end up on a different random site — each covered in ads, popups, and "click here to install our extension" banners. Half of them upload my data to their server for no reason.&lt;/p&gt;

&lt;p&gt;So this weekend I built &lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;&lt;strong&gt;DevKits&lt;/strong&gt;&lt;/a&gt; — a single site with 31 developer tools that all run &lt;strong&gt;100% in the browser&lt;/strong&gt;. No uploads, no accounts, no tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in it
&lt;/h2&gt;

&lt;p&gt;Right now, 31 tools across 9 categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON&lt;/strong&gt;: formatter, validator, JSONPath tester&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Converters&lt;/strong&gt;: JSON ↔ TypeScript / Go / YAML / CSV / XML&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encoding&lt;/strong&gt;: Base64, URL, HTML entities, image → data URL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt;: JWT decoder, MD5/SHA-256/SHA-512, password generator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Text&lt;/strong&gt;: regex tester, diff, case converter, word counter, Lorem Ipsum&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web&lt;/strong&gt;: color converter, user-agent parser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time&lt;/strong&gt;: Unix timestamp, cron expression parser&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt;: OpenAI/Claude/Gemini token counter&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Formatting&lt;/strong&gt;: SQL, XML, Markdown → HTML&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Live at &lt;a href="https://devkits.vip" rel="noopener noreferrer"&gt;devkits.vip&lt;/a&gt;. Open source? Not yet, but the whole project is deployable to Vercel in ~2 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use &lt;code&gt;it-tools.tech&lt;/code&gt; or &lt;code&gt;smallpdf&lt;/code&gt; or …?
&lt;/h2&gt;

&lt;p&gt;Fair question. Existing sites have some (or all) of these problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Bloat.&lt;/strong&gt; Loading 500KB of JS to format 200 characters of JSON.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ads.&lt;/strong&gt; Layout shifts on every visit.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy.&lt;/strong&gt; Some upload your input to a backend to "process" it — a red flag when your input is a JWT or an API response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cluttered UX.&lt;/strong&gt; "Please sign in to save your favorite tools." No thanks.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;DevKits does the opposite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Every First Load JS is under 130KB.&lt;/strong&gt; Most pages are 105–115KB.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero ads, zero cookies, zero cross-site tracking.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Everything runs client-side.&lt;/strong&gt; Even the MD5 implementation, the tokenizer, the cron parser — all pure functions in your browser.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Every tool page is a single URL you can bookmark.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tech stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15&lt;/strong&gt; with the App Router&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; (strict mode)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt; (with &lt;code&gt;@tailwindcss/typography&lt;/code&gt; for the Markdown preview)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vercel&lt;/strong&gt; for hosting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I picked Next.js specifically because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;SSG is a first-class citizen.&lt;/strong&gt; All 41 pages are pre-rendered at build time. No cold starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The &lt;code&gt;metadata&lt;/code&gt; API is a joy.&lt;/strong&gt; Per-page &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;canonical&lt;/code&gt;, OpenGraph, and JSON-LD structured data — all just typed objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File-based routing scales beautifully.&lt;/strong&gt; Adding a new tool is: (1) one entry in &lt;code&gt;tools.ts&lt;/code&gt;, (2) one &lt;code&gt;page.tsx&lt;/code&gt;, (3) one client component. The sitemap, homepage listing, and "related tools" links update automatically.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The tool registry pattern (my favorite part)
&lt;/h2&gt;

&lt;p&gt;The whole site is driven by a single &lt;code&gt;tools.ts&lt;/code&gt; config file:&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="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;slug&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="nl"&gt;title&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="nl"&gt;shortName&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="nl"&gt;description&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="nl"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ToolCategory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;keywords&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="nl"&gt;faq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;question&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="nl"&gt;answer&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Tool&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&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;slug&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json-formatter&lt;/span&gt;&lt;span class="dl"&gt;"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON Formatter &amp;amp; Validator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;shortName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;JSON Formatter&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Format, beautify, and validate JSON online. Free, fast, and 100% local...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;keywords&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="s2"&gt;json formatter&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="s2"&gt;json beautifier&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="s2"&gt;json validator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;faq&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="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Is my data uploaded?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No...&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="c1"&gt;// 30 more tools...&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From this single array, four things are auto-generated:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;sitemap.xml&lt;/code&gt;&lt;/strong&gt; — every tool becomes a URL entry&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Homepage listing&lt;/strong&gt; — grouped by category&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-page metadata&lt;/strong&gt; — title / description / canonical / OG / Twitter card&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JSON-LD structured data&lt;/strong&gt; — &lt;code&gt;SoftwareApplication&lt;/code&gt; + &lt;code&gt;FAQPage&lt;/code&gt; schema for rich Google search results&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The "related tools" section on each page is also just &lt;code&gt;tools.filter(t =&amp;gt; t.slug !== current.slug).slice(0, 6)&lt;/code&gt;. So internal linking is automatic.&lt;/p&gt;

&lt;p&gt;Adding a new tool takes about 20 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The token counter surprised me
&lt;/h2&gt;

&lt;p&gt;The AI Token Counter (for GPT-4o / Claude / Gemini) was the trickiest. Real tokenization requires shipping ~1MB of tokenizer vocabulary. Way too heavy for a "&lt;/p&gt;

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