<?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: Ramsudharsan Manoharan</title>
    <description>The latest articles on DEV Community by Ramsudharsan Manoharan (@ramsudharsan75).</description>
    <link>https://dev.to/ramsudharsan75</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%2F2467218%2Fa267aa5d-d1b2-45c8-9701-481c38fbfe45.jpg</url>
      <title>DEV Community: Ramsudharsan Manoharan</title>
      <link>https://dev.to/ramsudharsan75</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ramsudharsan75"/>
    <language>en</language>
    <item>
      <title>Remove an image background free, right in your browser</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Thu, 25 Jun 2026 12:57:59 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/remove-an-image-background-free-right-in-your-browser-2be9</link>
      <guid>https://dev.to/ramsudharsan75/remove-an-image-background-free-right-in-your-browser-2be9</guid>
      <description>&lt;p&gt;I needed one product photo on a transparent background — a mug, lifted off the kitchen counter, ready to drop onto a clean store listing. Five minutes of work. Then the first site I tried wanted me to start a subscription before it would let me download the result at full resolution.&lt;/p&gt;

&lt;p&gt;For one cutout. I closed the tab.&lt;/p&gt;

&lt;p&gt;So I built the thing I actually wanted: drop a photo in, get a transparent PNG back, no account, no watermark, no card. That's &lt;a href="https://toolstray.com/tools/background-remover" rel="noopener noreferrer"&gt;ToolsTray's Background Remover&lt;/a&gt;, and I'm obviously biased toward it — but read this for one idea regardless of the tool you end up using: &lt;em&gt;where the cutout is actually computed&lt;/em&gt;. That single detail is what lets a background remover be free and private in the same breath.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎬 &lt;strong&gt;Demo:&lt;/strong&gt; ToolsTray's Background Remover cutting a photo to a transparent PNG, entirely on-device — drag the slider to compare. &lt;a href="https://toolstray.com/blog/remove-image-background-free-in-browser" rel="noopener noreferrer"&gt;Watch it on the original article →&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The whole thing runs on your device
&lt;/h2&gt;

&lt;p&gt;Most "remove background" sites upload your image to their server, run the model there, and bill you for the compute. That's why they need a subscription — someone has to pay for the GPUs.&lt;/p&gt;

&lt;p&gt;ToolsTray flips that. A small AI segmentation model — a &lt;code&gt;u2netp&lt;/code&gt; model, from the U2-Net family — runs &lt;em&gt;inside your browser&lt;/em&gt; through an in-browser ONNX runtime. Your photo is handed to a model that's already sitting on your own machine; it never gets posted anywhere. The only thing that crosses the network is the model file coming &lt;em&gt;down&lt;/em&gt; to you, once. Your image only ever moves between your tab and your screen. With no GPU running up a bill on my end, there's simply nothing to put a price on — that's the whole reason a tool this heavy can be free.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you get back: a transparent PNG
&lt;/h2&gt;

&lt;p&gt;You drop in a photo, wait a moment while it processes, and download a PNG with the subject cut out and the background gone — actually transparent, not a fake white box. That's the format you want for almost everything downstream: layering the subject onto a design, a thumbnail, a sticker, a banner, a marketplace listing.&lt;/p&gt;

&lt;p&gt;If you'd rather not deal with transparency, you can composite the cutout onto a solid color instead — pick white for a clean product shot, or any color for a headshot backdrop — and export a finished flat image. Same flow, one extra choice.&lt;/p&gt;

&lt;h2&gt;
  
  
  First run downloads the model once, then it's cached
&lt;/h2&gt;

&lt;p&gt;Here's the one wait worth knowing about. The first time you use the tool, your browser downloads the model and runtime — a few megabytes — before it can do anything. On a normal connection that's a few seconds, once.&lt;/p&gt;

&lt;p&gt;After that, your browser caches the model. Every later cutout skips the download entirely and starts almost instantly. So the very first image feels a touch slower than you'd expect; the tenth feels immediate. It's a one-time tax, not a per-image one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Doing a batch? Run your first image and let the model finish downloading before you queue up the rest. Once it's cached, the remaining photos process back-to-back with no fetch in between.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The honest tradeoff: fine hair and wispy edges
&lt;/h2&gt;

&lt;p&gt;I won't oversell this. An on-device model is small by necessity — it has to fit in a browser download and run on your laptop in seconds — and that trades a little edge precision for the privacy and the price.&lt;/p&gt;

&lt;p&gt;In practice: a clear subject with decent contrast — a product on a plain-ish surface, a person against a wall, a pet — cuts cleanly. But fly-away strands of hair, fur, or anything thin and wispy against a busy background is the hard case for any segmentation model, and a compact one will sometimes leave those edges a bit rough where a paid cloud service might nail them. If a pixel-perfect hairline matters for a hero image, a heavier paid tool can still win. For the everyday "I need this off its background, now," the gap rarely matters — and a higher-resolution, higher-contrast source photo closes most of it.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it works best (and how to help it)
&lt;/h2&gt;

&lt;p&gt;A few seconds of setup gets you a noticeably cleaner cut:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Contrast is everything.&lt;/strong&gt; A subject that stands out from what's behind it cuts far better than one that blends in. A dark jacket against a dark couch is the worst case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go higher-res.&lt;/strong&gt; More pixels on the subject gives the model more to work with, especially around edges. A cropped-in phone photo beats a tiny thumbnail.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One clear subject.&lt;/strong&gt; The model finds &lt;em&gt;the&lt;/em&gt; subject. A single mug, person, or animal in frame is the sweet spot; a cluttered scene with five competing objects is not.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why I'd reach for this first
&lt;/h2&gt;

&lt;p&gt;Most of the time you don't need a studio-grade matte — you need the background gone so you can get on with the listing, the slide, or the post. Free, instant after the first run, nothing uploaded, no watermark on the way out. For the once-a-week cutout that doesn't justify a subscription, that's the whole job done on your own machine.&lt;/p&gt;

&lt;p&gt;Drop a photo in and see how clean the edge comes out on your image — it's the honest test, and it costs you nothing.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it — free, no signup, runs in your browser:&lt;/strong&gt; &lt;a href="https://toolstray.com/tools/background-remover" rel="noopener noreferrer"&gt;Background Remover on ToolsTray&lt;/a&gt;&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Compress a PDF under 1 MB for email — free, no upload</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Thu, 25 Jun 2026 12:55:07 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/compress-a-pdf-under-1-mb-for-email-free-no-upload-2d8j</link>
      <guid>https://dev.to/ramsudharsan75/compress-a-pdf-under-1-mb-for-email-free-no-upload-2d8j</guid>
      <description>&lt;p&gt;The upload form was blunt about it: "File must be under 1 MB." My scanned PDF was 6.4 MB. The job application wouldn't go a step further until I fixed that.&lt;/p&gt;

&lt;p&gt;If you've hit the same wall — a portal that caps uploads at 1 MB or 2 MB, or an email that bounces a fat attachment — here's how to get a PDF under the limit in about thirty seconds, for free, and without handing your document to anyone.&lt;/p&gt;

&lt;p&gt;I'll use &lt;a href="https://toolstray.com/tools/pdf-compress" rel="noopener noreferrer"&gt;ToolsTray's Compress PDF&lt;/a&gt; because I built it, but the &lt;em&gt;why&lt;/em&gt; matters more than the &lt;em&gt;which&lt;/em&gt; — so I'll explain what's actually making your file big and what a good compressor should do about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why your PDF is so big (it's the images)
&lt;/h2&gt;

&lt;p&gt;A page of text is tiny — a few kilobytes. What blows a PDF up to megabytes is &lt;strong&gt;images&lt;/strong&gt;: scanned pages, phone photos, the screenshots in a slide export. A 12-page scanned contract is really twelve photos in a trench coat.&lt;/p&gt;

&lt;p&gt;That points straight at the fix: squeeze the &lt;em&gt;images&lt;/em&gt; and leave everything else alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap: compressors that flatten every page
&lt;/h2&gt;

&lt;p&gt;Here's the honest tradeoff, and it's the thing a lot of "free PDF compressor" sites get wrong. Many shrink a PDF by turning &lt;strong&gt;every page into one flat image&lt;/strong&gt;. The file does get smaller — but your crisp, selectable text becomes a blurry picture. You can't search it, you can't copy a line out of it, and it looks soft on screen.&lt;/p&gt;

&lt;p&gt;A better compressor recompresses only the embedded images and &lt;strong&gt;copies the text and vector graphics through untouched&lt;/strong&gt;. ToolsTray's Compress PDF re-encodes each photo with the MozJPEG encoder at the quality you pick, so the words stay sharp and selectable. That's the one thing I'd check for in whatever tool you choose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get under 1 MB in three steps
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://toolstray.com/tools/pdf-compress" rel="noopener noreferrer"&gt;Compress PDF&lt;/a&gt; and drop your file in. Nothing uploads — it runs in your browser, which matters when the PDF is a contract or an ID.&lt;/li&gt;
&lt;li&gt;Choose &lt;strong&gt;Target size&lt;/strong&gt; and type your limit in KB — &lt;code&gt;1000&lt;/code&gt; for 1 MB, or &lt;code&gt;200&lt;/code&gt; if a form is stricter.&lt;/li&gt;
&lt;li&gt;Download. The tool steps through progressively stronger compression and keeps the lightest result that still fits under your number.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffgz2n3ms37xh6n9s3szi.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%2Ffgz2n3ms37xh6n9s3szi.webp" alt="ToolsTray's Compress PDF in Target-size mode: a 1.9 MB scanned PDF compressed to 325 KB, an 84% reduction, processed on-device." width="799" height="393"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Target-size mode in action: a 1.9 MB scan down to 325 KB (−84%), all on your device.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you don't need an exact ceiling, skip Target size and pick &lt;strong&gt;Balanced&lt;/strong&gt; — the right call for most reports and decks. Use &lt;strong&gt;Light&lt;/strong&gt; when the photos must stay crisp, &lt;strong&gt;Strong&lt;/strong&gt; when you simply have to make it small.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Email limits are far bigger than upload-form limits. Gmail and most providers cap attachments around 25 MB, but job portals, government forms, and visa sites often demand 1 MB — sometimes 200 KB. Compress to the smallest limit you actually need to clear, not smaller.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  When it barely shrinks (and that's fine)
&lt;/h2&gt;

&lt;p&gt;Compression isn't magic. If a PDF is &lt;strong&gt;mostly text&lt;/strong&gt;, already optimized, or built from image types that can't be safely recompressed, there's little to remove — and a good tool tells you the smallest size it managed instead of mangling the file. ToolsTray's will never hand you a copy &lt;em&gt;larger&lt;/em&gt; than the original.&lt;/p&gt;

&lt;p&gt;If a text-only PDF is somehow huge, the weight is usually embedded fonts or junk metadata, not images — a different problem with a different fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "no upload" is the part I care about
&lt;/h2&gt;

&lt;p&gt;When compression runs in your browser, your document never touches a server. For a payslip, a signed contract, or a passport scan, that isn't a marketing line — it's the difference between "trust this random website with my ID" and "the file never left my laptop." Open your browser's network tab while you use it and watch: nothing goes out.&lt;/p&gt;

&lt;p&gt;It's also why it's free with no sign-up. There's no server doing the work to pay for — your own device does it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try it — free, no signup, runs in your browser:&lt;/strong&gt; &lt;a href="https://toolstray.com/tools/pdf-compress" rel="noopener noreferrer"&gt;Compress PDF on ToolsTray&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to email a large, sensitive PDF without uploading it to compress?</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Thu, 25 Jun 2026 07:21:02 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/how-to-email-a-large-sensitive-pdf-without-uploading-it-fde</link>
      <guid>https://dev.to/ramsudharsan75/how-to-email-a-large-sensitive-pdf-without-uploading-it-fde</guid>
      <description>&lt;p&gt;A friend texted me on a Sunday night, half-panicking. She was applying for a flat, and the rental portal wanted her last three payslips as one PDF — under 2 MB. Hers was nine. She'd already found a "compress PDF" site, uploaded the file, and was watching the progress bar when she stopped and asked: "this is fine, right? it's got my salary and my account number on it."&lt;/p&gt;

&lt;p&gt;It isn't, really — not a disaster every time, but not something I'd do with a payslip. And it's such a common trap, because the documents too big to email are almost always the ones you'd least want sitting on a stranger's server: payslips, bank statements, a scanned signed contract, ID proofs. Uploading those to the first search result is precisely the wrong instinct.&lt;/p&gt;

&lt;p&gt;So here's how I deal with it instead, and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why these are the PDFs that bounce
&lt;/h2&gt;

&lt;p&gt;A bank statement is a few kilobytes of text wrapped around a logo and, if you scanned or photographed it, full pages saved as phone-camera-resolution images. The words weigh almost nothing; the pictures are the whole problem. That's also the good news — bring the images down to a sane size and the file drops hard while the text stays exactly as it was.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the email limit actually is
&lt;/h2&gt;

&lt;p&gt;The error messages are vague, so a quick reality check. Gmail caps attachments at 25 MB. Outlook.com is lower, around 20 MB. And there's a catch nobody mentions: attachments are re-encoded for transit and travel about a third larger than the file sitting on your disk, so a 20 MB PDF can trip a 25 MB limit. Plenty of company mail servers also quietly cap what they'll &lt;em&gt;accept&lt;/em&gt;. Treat "under 25 MB" as "comfortably under 20."&lt;/p&gt;

&lt;h2&gt;
  
  
  Shrink it without uploading it
&lt;/h2&gt;

&lt;p&gt;Here's the part that matters for a payslip: you don't have to send it anywhere to make it smaller. &lt;a href="https://toolstray.com/tools/pdf-compress" rel="noopener noreferrer"&gt;ToolsTray's Compress PDF&lt;/a&gt; does the whole thing in your browser — it opens the file on your device, re-encodes the images inside it, and rebuilds a lighter copy locally. Nothing leaves the tab. Drop the file in, choose Balanced, download. The text stays sharp and selectable because only the images are touched — which is exactly what separates it from tools that "compress" a PDF by flattening every page into a single picture.&lt;/p&gt;

&lt;h2&gt;
  
  
  When the form wants 100 KB, not 25 MB
&lt;/h2&gt;

&lt;p&gt;The nastier version is the government form or job portal with a hard ceiling — 200 KB, sometimes 100 KB. I built the &lt;strong&gt;Target size&lt;/strong&gt; option for exactly that, after a form rejected a scan of mine for being 240 KB without so much as hinting how far over the line I was. You type the limit; it keeps trying stronger compression until it finds the lightest result that still fits — or tells you the smallest it managed, if the file simply can't get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "in your browser" isn't just a slogan here
&lt;/h2&gt;

&lt;p&gt;For a meme PDF, who cares where it gets compressed. For a document with your salary, account number, and home address on it, that's the entire question. A file you upload sits on someone else's server, in their logs, under their privacy policy, for however long they keep it. Processed on your device, there's nothing to leak — it never crosses the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  When compressing won't help — and what to do instead
&lt;/h2&gt;

&lt;p&gt;Honestly, it won't rescue every file. A PDF that's mostly text — a plain letter, a generated invoice — has almost no image data to drop, so it'll barely move, and the tool tells you so rather than pretend. (It also never hands you a file bigger than the one you started with.) If you're still over the limit, &lt;a href="https://toolstray.com/tools/pdf-split" rel="noopener noreferrer"&gt;split it&lt;/a&gt; and send two emails, or &lt;a href="https://toolstray.com/tools/image-to-pdf" rel="noopener noreferrer"&gt;rebuild it from fewer pages&lt;/a&gt;. And yes — a heavy cloud service with aggressive downsampling might squeeze out a little more than an on-device tool can. For a bank statement, that's not a trade I'd make.&lt;/p&gt;

&lt;p&gt;My friend's payslips went from nine megabytes to about six hundred kilobytes in a few seconds, never left her laptop, and the portal took them on the first try. That's the bar I aim for: small enough to send, private enough to stop thinking about.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>webdev</category>
      <category>showdev</category>
      <category>software</category>
    </item>
    <item>
      <title>Dont decode JWT on random sites - verify if they are sending it to backend servers! How though?</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Sun, 14 Jun 2026 18:06:53 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/dont-decode-jwt-on-random-sites-verify-if-they-are-sending-it-to-backend-servers-how-though-2mha</link>
      <guid>https://dev.to/ramsudharsan75/dont-decode-jwt-on-random-sites-verify-if-they-are-sending-it-to-backend-servers-how-though-2mha</guid>
      <description>&lt;p&gt;A JWT usually carries who you are and what you're allowed to do. When you debug one, you tend to paste the whole token into the first "JWT decoder" search result — and a lot of those sites send that token straight to their own server to decode it. For a throwaway test token that's harmless. For a real access token from staging or production, you've just handed a stranger a working credential.&lt;/p&gt;

&lt;p&gt;You don't have to guess which kind of site you're on. Here's how I check.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a JWT decoder can be risky
&lt;/h2&gt;

&lt;p&gt;A JWT isn't encrypted — it's signed. The header and payload are just Base64URL-encoded JSON, so anything that can read the token can read every claim inside it: user id, email, roles, expiry, sometimes more. If the token hasn't expired, it's still usable. A decoder that ships your token off to a backend has, for a moment, a valid credential in its logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check what a decoder does with your token
&lt;/h2&gt;

&lt;p&gt;Open your browser's dev tools, go to the &lt;strong&gt;Network&lt;/strong&gt; tab, clear it, then paste a token into the decoder. Watch what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No request fires&lt;/strong&gt; → the page decoded it in your browser. Safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A request fires&lt;/strong&gt; with your token in the URL or POST body → it went to their server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's the whole test. It takes about ten seconds and it's the only way to know for sure, regardless of what the marketing copy claims.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can decode the payload yourself
&lt;/h2&gt;

&lt;p&gt;A JWT is three Base64URL chunks joined by dots: &lt;code&gt;header.payload.signature&lt;/code&gt;. The first two are just JSON. You can decode either part with any Base64 tool — no special "JWT" service required:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;atob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/-/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/_/g&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you've seen that it's only Base64, the "send it to our server to decode" sites stop making sense. There's nothing on the server that your browser can't do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decode it locally instead
&lt;/h2&gt;

&lt;p&gt;This is exactly why &lt;a href="https://toolstray.com/tools/jwt-decoder" rel="noopener noreferrer"&gt;ToolsTray JWT decoder&lt;/a&gt; runs entirely in the browser — paste a token, read the claims, and nothing leaves the tab. It's the same convenience as the popular sites without the token ever crossing the network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before you paste: never share the signing secret
&lt;/h2&gt;

&lt;p&gt;Reading the payload is safe. &lt;strong&gt;Verifying&lt;/strong&gt; the signature is where people leak the thing that actually matters.&lt;/p&gt;

&lt;p&gt;Verifying a JWT needs the signing secret or private key. Never paste that into a website — a secret is far more sensitive than a single token. Verify signatures locally, or in code you control.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>WebAssembly turned my "static" site into a zero-backend app platform</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Sat, 13 Jun 2026 18:10:28 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/webassembly-turned-my-static-site-into-a-zero-backend-app-platform-3ip6</link>
      <guid>https://dev.to/ramsudharsan75/webassembly-turned-my-static-site-into-a-zero-backend-app-platform-3ip6</guid>
      <description>&lt;p&gt;For the longest time I treated "static site" and "does real work" as mutually exclusive. Static meant brochureware. Anything heavier like resizing an image obviously needed a server.&lt;/p&gt;

&lt;p&gt;Then I built a site full of tools that do that heavy work and shipped the whole thing as static files on a CDN with &lt;strong&gt;no backend at all&lt;/strong&gt;. The thing that made it possible — and changed how I think about web architecture — is WebAssembly.&lt;/p&gt;

&lt;p&gt;I'll use one tool as the running example: an &lt;strong&gt;image compressor&lt;/strong&gt;. Same lessons apply to everything else I've built, but one concrete case is clearer than a feature list.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mental shift: the browser &lt;em&gt;is&lt;/em&gt; the server
&lt;/h2&gt;

&lt;p&gt;The old model: user uploads a file → your server does the work → sends the result back. You pay for that server, secure it, scale it, and the user's data takes a round trip through your infra.&lt;/p&gt;

&lt;p&gt;WASM flips it. Ship the &lt;em&gt;computation&lt;/em&gt; to the browser as a &lt;code&gt;.wasm&lt;/code&gt; module and the user's device does the work. For the compressor, I use a WASM build of the same codecs you'd find in native tools (MozJPEG/WebP/AVIF). The "server" becomes a dumb file host. No upload, no round trip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefit 1: client-side processing is a privacy feature you get for free
&lt;/h2&gt;

&lt;p&gt;When you compress a photo and the file &lt;em&gt;never leaves your device&lt;/em&gt;, "we don't see your data" stops being a privacy-policy line and becomes an architectural fact. There's no upload — you can watch the network tab and confirm it. I don't have a server that &lt;em&gt;could&lt;/em&gt; see your photo, and that costs me nothing to provide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefit 2: "fast loading" is more nuanced than it sounds — and mostly a win
&lt;/h2&gt;

&lt;p&gt;People assume WASM = bloat = slow. The reality is more interesting.&lt;/p&gt;

&lt;p&gt;The trick is that &lt;strong&gt;the page loads instantly and the WASM loads lazily.&lt;/strong&gt; My pages are pre-rendered HTML, so they paint immediately, stay fully indexable, and keep Core Web Vitals green. The codec only gets fetched when you actually click "Compress."&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;// Nothing heavy ships in the initial bundle.&lt;/span&gt;
&lt;span class="c1"&gt;// The codec is dynamic-imported on first real use, then cached.&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;compress&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;encode&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="s2"&gt;@jsquash/webp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// wasm loads here&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fileToImageData&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that first load it's instant — and there's no upload/download round trip. A 15 MB photo never travels anywhere; it's processed in place at near-native speed. A server tool would have you upload 15 MB, wait, and download the result. Locally it's often faster &lt;em&gt;and&lt;/em&gt; the bytes never leave.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefit 3: it scales to infinity and costs almost nothing
&lt;/h2&gt;

&lt;p&gt;This still feels slightly illegal. Hosting is a CDN serving static files. No compute to autoscale, no per-request cost. Whether 10 people or 100,000 people compress an image today, my bill is basically flat — because &lt;em&gt;their&lt;/em&gt; CPUs did the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Now the parts that hurt (the honest section)
&lt;/h2&gt;

&lt;p&gt;WASM is a game changer, but I collected scars. Budget for these:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;First-run latency is real.&lt;/strong&gt; The codec is a few hundred KB; heavier engines (ML models, etc.) are several MB. Lazy-loading hides it from everyone who never uses that tool, but the &lt;em&gt;first&lt;/em&gt; hit waits while the module downloads and instantiates. I show an explicit "loading…" state so it doesn't feel broken.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Threads want &lt;code&gt;SharedArrayBuffer&lt;/code&gt;, which wants cross-origin isolation.&lt;/strong&gt; The fast multithreaded paths need &lt;code&gt;COOP&lt;/code&gt;/&lt;code&gt;COEP&lt;/code&gt; headers, and turning those on globally can break third-party embeds, ads, and analytics. I had to be deliberate about where I require isolation versus falling back to a single-threaded path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bundler/serving friction is constant.&lt;/strong&gt; You'll fight your build tool over &lt;code&gt;.wasm&lt;/code&gt; MIME types, worker output format, and keeping &lt;code&gt;new URL('x.wasm', import.meta.url)&lt;/code&gt; resolution intact. It works, but it wasn't "npm install and go."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory and debugging are worse.&lt;/strong&gt; A huge input can OOM the tab — and a WASM OOM isn't a graceful 500, the tab can just die, so you need size guardrails. And when something breaks &lt;em&gt;inside&lt;/em&gt; the module, you don't get the comfortable JS stack trace; source-map support is still patchy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Would I do it again? Without hesitation.
&lt;/h2&gt;

&lt;p&gt;The cons are mostly one-time setup pain and first-load UX work. The benefits — privacy by architecture, no backend to run or secure, flat costs at any scale, near-native speed with no round trips — are permanent and compound.&lt;/p&gt;

&lt;p&gt;The real unlock wasn't the compressor itself. It was realizing that "static" no longer caps what the product can &lt;em&gt;do&lt;/em&gt;. It only caps where the code &lt;em&gt;runs&lt;/em&gt; — and the browser turned out to be a perfectly good place to run it.&lt;/p&gt;

&lt;h2&gt;
  
  
  See it in action
&lt;/h2&gt;

&lt;p&gt;If you want to poke at this for real, I put it into &lt;a href="https://toolstray.com" rel="noopener noreferrer"&gt;&lt;strong&gt;ToolsTray&lt;/strong&gt;&lt;/a&gt;. Try the image compressor, open your network tab while you use it, and watch: the codec loads once, and your image never goes anywhere. That's the whole point.&lt;/p&gt;

&lt;p&gt;Leave a like if you loved it! Happy to answer questions about the WASM setup in the comments.&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>staticwebapps</category>
      <category>performance</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How I auto-prioritize page content on a static site (no backend)</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Mon, 08 Jun 2026 18:31:14 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/how-i-auto-prioritize-page-content-on-a-static-site-no-backend-1e79</link>
      <guid>https://dev.to/ramsudharsan75/how-i-auto-prioritize-page-content-on-a-static-site-no-backend-1e79</guid>
      <description>&lt;p&gt;I run a static site with a growing pile of small tools on it. The homepage shows a "Popular" row near the top, and for a while I just hand-picked what went in it. That worked until it didn't — the picks went stale, my guesses about what people actually used were usually wrong, and every new tool meant re-ranking a list by hand.&lt;/p&gt;

&lt;p&gt;The catch is that a static site has no server at request time to do the deciding. So people reach for one of two bad options: hardcode the order and let it rot, or bolt on a backend and stop being static.&lt;/p&gt;

&lt;p&gt;There's a third option that's simpler than both: &lt;strong&gt;decide the order at build time, from real data, and bake it into the HTML.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One ranking, computed once
&lt;/h2&gt;

&lt;p&gt;You don't need per-visitor personalization to do a good job here. A single &lt;em&gt;global&lt;/em&gt; ranking — what's popular across everyone — gets you most of the value at zero runtime cost. Compute it during the build; the CDN serves plain HTML after.&lt;/p&gt;

&lt;p&gt;The ranking is two signals added together: an editorial seed I set by hand, plus a traffic score from analytics.&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rankByPopularity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;ToolMeta&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
  &lt;span class="nx"&gt;gaScores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PopularityScores&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;ToolMeta&lt;/span&gt;&lt;span class="p"&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="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;]&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;tool&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="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;score&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="nx"&gt;popularity&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gaScores&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="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="mi"&gt;0&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="nf"&gt;sort&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;score&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;a&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="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;localeCompare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&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="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;)&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;scored&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;scored&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tool.popularity&lt;/code&gt; is the seed baked into each tool's metadata. &lt;code&gt;gaScores[slug]&lt;/code&gt; is the real traffic number. New tools have no traffic yet, so &lt;code&gt;?? 0&lt;/code&gt; lets the seed carry them until the data shows up — cold-start solved in one operator. The alphabetical tiebreak keeps the order stable so it never flickers between builds.&lt;/p&gt;

&lt;p&gt;It's a pure function: no DOM, no fetch, no clock. That means I can unit-test the ranking with a fake &lt;code&gt;gaScores&lt;/code&gt; object instead of rendering a browser to find out what came out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the traffic number comes from
&lt;/h2&gt;

&lt;p&gt;Once a week a small script hits the Google Analytics API, pulls 28 days of pageviews per tool page, normalizes the busiest to 1000, and writes a flat JSON file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&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;"age-calculator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"apr-calculator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;182&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"base64"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;91&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;p&gt;Then I commit it. The build imports it like any other module — no network call in CI, no API key in the critical path. If GA is down, the build doesn't care; it uses the last committed numbers.&lt;/p&gt;

&lt;p&gt;This is the part I'd argue about. Don't call the API at build time — commit the JSON. You get reproducible builds, traffic shifts you can read in a git diff, and rollback like any other file. The freshness you give up is a week, which does not matter for a popularity list.&lt;/p&gt;

&lt;p&gt;Viola! You have a automatic prioritization mechanism that works in static sites.&lt;/p&gt;

&lt;p&gt;See it in action here - &lt;a href="https://toolstray.com" rel="noopener noreferrer"&gt;ToolsTray&lt;/a&gt;, a free set of browser tools — the homepage ordering there is exactly this pipeline running. Explore it yourself and leave a like if you enjoyed it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>astro</category>
      <category>seo</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Toolstray - Free and fast web tools, no-signup, no-watermark</title>
      <dc:creator>Ramsudharsan Manoharan</dc:creator>
      <pubDate>Sat, 06 Jun 2026 16:27:00 +0000</pubDate>
      <link>https://dev.to/ramsudharsan75/i-built-25-free-no-signup-browser-tools-heres-what-and-why-47fk</link>
      <guid>https://dev.to/ramsudharsan75/i-built-25-free-no-signup-browser-tools-heres-what-and-why-47fk</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;a href="https://toolstray.com" rel="noopener noreferrer"&gt;ToolsTray&lt;/a&gt;&lt;/strong&gt; is a collection of 40+ small web tools — calculators, converters, generators and formatters — each built to do one job quickly and get out of your way.&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%2Fqrze4ygpxqcq7gcba2i6.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%2Fqrze4ygpxqcq7gcba2i6.png" alt="toolstray screenshot" width="799" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I built it&lt;/strong&gt;: I kept hitting the same friction — search basic, land on a slow page buried by paywalls (known after processing), watermark addition and forced logins for something that should take two seconds.&lt;/p&gt;

&lt;p&gt;So I made the opposite: open the tool, use it, leave. No signup, no install, no paywall.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A few of the tools live today:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QR code generator (PNG/SVG)&lt;/li&gt;
&lt;li&gt;Image compressor + resizer&lt;/li&gt;
&lt;li&gt;Base64 / URL / HTML-entity encoders, hash + UUID generators, number-base converter&lt;/li&gt;
&lt;li&gt;JSON formatter, regex tester&lt;/li&gt;
&lt;li&gt;Loan/EMI, mortgage, SIP, compound-interest, percentage and age calculators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tech&lt;/strong&gt;: static Astro (islands) on Cloudflare, Tailwind v4 + Basecoat (no React) — adding a tool is adding one module, Typescript, Biome, Vitest.&lt;/p&gt;

&lt;p&gt;Try it, bookmark it! It's young, so the catalog has gaps. What tool would you want next, and what felt rough?&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>sideprojects</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
