<?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: Jeffrey Hamilton</title>
    <description>The latest articles on DEV Community by Jeffrey Hamilton (@jeffrey_hamilton6399).</description>
    <link>https://dev.to/jeffrey_hamilton6399</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%2F4000955%2Fa3d347aa-4cea-43d3-a6f6-0fbc0a777154.jpg</url>
      <title>DEV Community: Jeffrey Hamilton</title>
      <link>https://dev.to/jeffrey_hamilton6399</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jeffrey_hamilton6399"/>
    <language>en</language>
    <item>
      <title>I built a PDF merger that never uploads your files — here's how published: false</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 18 Aug 2026 13:00:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-built-a-pdf-merger-that-never-uploads-your-files-heres-howpublished-false-1iik</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-built-a-pdf-merger-that-never-uploads-your-files-heres-howpublished-false-1iik</guid>
      <description>&lt;p&gt;MergePDF is a 100% client-side PDF tool. No backend, no uploads, no sign-up. Here's the architecture, the tricky parts, and why privacy is a feature, not a setting.&lt;br&gt;
Every tax season, the same thing happens. Someone in my family asks me to merge a few PDFs. They Google "merge PDF." They click the first result — a slick, friendly-looking site. They upload their tax returns to a server they've never heard of.&lt;/p&gt;

&lt;p&gt;That bothered me.&lt;/p&gt;

&lt;p&gt;So I built MergePDF. It merges, splits, rotates, and rearranges PDF pages — and your files never leave your browser. No backend. No sign-up. No ads. No tracking.&lt;/p&gt;

&lt;p&gt;iLovePDF uploads your tax returns. We don't.&lt;/p&gt;

&lt;p&gt;This post is about how it works, the parts that were harder than I expected, and why "client-side only" is a design philosophy, not just a technical choice.&lt;/p&gt;

&lt;p&gt;The pitch in 30 seconds&lt;br&gt;
Drop one or more PDFs onto the page. You get a grid of page thumbnails — real, rendered previews of every page. Drag to reorder. Click to select. Rotate, delete, extract a range. Merge everything into one file, or split into single-page PDFs zipped up. Download. Done.&lt;/p&gt;

&lt;p&gt;Your browser does all of it. There is no server processing documents. There isn't even a server to process documents.&lt;/p&gt;

&lt;p&gt;The stack&lt;br&gt;
It's a Next.js app, but honestly Next.js is just the host here. The interesting parts are all client-side libraries doing real work:&lt;/p&gt;

&lt;p&gt;No database. No API routes. No auth. No analytics. The only thing in localStorage is your theme preference.&lt;/p&gt;

&lt;p&gt;Drag-to-reorder that doesn't fight tap-to-select&lt;br&gt;
This one took three attempts. The requirement:&lt;/p&gt;

&lt;p&gt;Tap a thumbnail → select it (emerald ring)&lt;br&gt;
Shift-tap → select a range&lt;br&gt;
Long-press + drag → reorder&lt;br&gt;
Swipe on mobile → scroll the grid (don't drag)&lt;br&gt;
The conflict: if the whole card is the drag handle, taps get swallowed. If only a tiny grip icon is the handle, nobody finds it (especially on mobile, where there's no hover).&lt;/p&gt;

&lt;p&gt;So split produces a ZIP. fflate's zip packages every single-page PDF into one download. Rotations are honored here too — each split page keeps its rotation via setRotation.&lt;/p&gt;

&lt;p&gt;What I deliberately left out&lt;br&gt;
No accounts. Nothing to phish, nothing to leak, nothing to manage.&lt;br&gt;
No analytics. I don't know how many people use it, and I'm fine with that.&lt;br&gt;
No paid tier. No watermarks on free output, no "upgrade to merge more than 5 pages."&lt;br&gt;
No "AI features." I considered adding "summarize this PDF" and decided no. It would require either a server (defeats the purpose) or running a model in the browser (heavy, and most users don't want it). The tool does one thing well.&lt;br&gt;
Limits, honestly stated&lt;br&gt;
Client-side has real constraints:&lt;/p&gt;

&lt;p&gt;Memory. A 500-page PDF will strain a mobile browser. I cap at 50 pages on mobile, 200 on desktop, and warn instead of silently truncating.&lt;br&gt;
Encrypted PDFs. pdf-lib loads them with ignoreEncryption: true, but if they're actually password-protected, rendering fails gracefully (the thumbnail shows "Render failed" and the page is skipped, never a crash).&lt;br&gt;
No OCR. If you need text extraction from scanned images, this isn't the tool. That's a server-or-model problem.&lt;br&gt;
Try it&lt;br&gt;
The code is on GitHub: &lt;a href="https://github.com/JeffreyHamilton6399/MergePDF" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/MergePDF&lt;/a&gt;. It deploys to Vercel with zero environment variables — import the repo, click deploy, you're done.&lt;/p&gt;

&lt;p&gt;If you build something with it, or find a bug, I'd love to hear about it. And if this is the kind of tool you'd rather use than the one that uploads your tax returns — well, that's the whole point.&lt;/p&gt;

&lt;p&gt;If you found this useful, I write about client-side web stuff and don't have a newsletter to plug. I do have a Buy Me a Coffee if you're feeling generous.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>privacy</category>
      <category>pdf</category>
    </item>
    <item>
      <title>I built a file transfer tool where the files never touch a server (WebRTC P2P)</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 11 Aug 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-built-a-file-transfer-tool-where-the-files-never-touch-a-server-webrtc-p2p-l4m</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-built-a-file-transfer-tool-where-the-files-never-touch-a-server-webrtc-p2p-l4m</guid>
      <description>&lt;p&gt;Every time you need to move a file from your phone to your computer (or vice versa), your options are:&lt;/p&gt;

&lt;p&gt;Email it (25MB limit, uploads to a server)&lt;br&gt;
Google Drive (uploads to Google's servers, stored forever)&lt;br&gt;
WeTransfer (uploads to their servers, 2GB limit)&lt;br&gt;
AirDrop (Apple only)&lt;br&gt;
None of these are great for privacy. Your files are sitting on someone else's server.&lt;/p&gt;

&lt;p&gt;So I built FileBeam — it transfers files directly between two devices via WebRTC. No cloud, no uploads, no size limits.&lt;/p&gt;

&lt;p&gt;Try it: filebeam-ten.vercel.app&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/filebeam" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/filebeam&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it works&lt;br&gt;
text&lt;/p&gt;

&lt;p&gt;Device A (Sender)          Device B (Receiver)&lt;br&gt;
     │                          │&lt;br&gt;
     │ ── WebRTC P2P ──────────│  (files go DIRECTLY, encrypted)&lt;br&gt;
     │                          │&lt;br&gt;
     └── Signaling relay ──────┘&lt;br&gt;
         (6-digit code + handshake only)&lt;br&gt;
         (NEVER sees file data)&lt;br&gt;
Device A: Drop files → get a 6-digit code + QR code&lt;br&gt;
Device B: Enter the 6-digit code (or scan QR)&lt;br&gt;
Files transfer directly from A to B via WebRTC data channels (end-to-end encrypted via DTLS)&lt;br&gt;
The signaling server only passes the 6-digit code and connection handshake — it NEVER sees the files&lt;br&gt;
The architecture&lt;br&gt;
Frontend: Next.js 16 + Tailwind + shadcn/ui (hosted on Vercel)&lt;br&gt;
Signaling: A tiny socket.io relay (~130 lines, hosted on Render's free tier)&lt;br&gt;
Transfer: WebRTC RTCPeerConnection + data channels (16KB chunks)&lt;br&gt;
Encryption: WebRTC DTLS (built into the protocol — files are encrypted in transit)&lt;br&gt;
Key technical decisions&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;WebRTC data channels (not HTTP)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Files stream in 16KB chunks via RTCDataChannel. This allows true peer-to-peer transfer — the files go directly from device A to device B, never passing through any server.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A minimal signaling relay&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A ~130-line socket.io server relays only the 6-digit code and WebRTC SDP/ICE candidates so the two devices can find each other. It never receives, stores, or sees file data, file names, or file sizes. The room is destroyed when the transfer ends or a device disconnects.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;6-digit codes = 1 million possibilities&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Brute force is impractical for ephemeral rooms that auto-destroy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stream large files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Files are read via file.stream().getReader() and sent in 16KB chunks — meaning even multi-GB files can transfer without loading into memory.&lt;/p&gt;

&lt;p&gt;The privacy model (honest version)&lt;br&gt;
  Files go direct — file bytes, names, and sizes travel only over the encrypted peer-to-peer data channel. No server ever receives or stores them.&lt;br&gt;
 End-to-end encrypted — WebRTC DTLS encryption is built into the protocol.&lt;br&gt;
 No file storage anywhere — nothing is saved on any server, ever.&lt;br&gt;
 No accounts, no tracking, no analytics.&lt;br&gt;
 What the signaling server sees: the 6-digit code and connection info (IPs/ICE candidates) needed to pair the devices. That's inherent to WebRTC — two devices need to exchange connection info before they can connect directly. It never sees file data.&lt;br&gt;
 Open source — read every line of code.&lt;br&gt;
Try it&lt;br&gt;
 Live: filebeam-ten.vercel.app&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/filebeam" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/filebeam&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Email uploads your files. Google Drive stores them forever. FileBeam sends them directly.&lt;/p&gt;

&lt;p&gt;FileBeam is built with Next.js 16, WebRTC, Tailwind CSS, and shadcn/ui. The signaling relay runs on Render's free tier.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>privacy</category>
      <category>webrtc</category>
    </item>
    <item>
      <title>I built a privacy-first face blurring tool that runs entirely in your browser</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 11 Aug 2026 11:44:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-built-a-privacy-first-face-blurring-tool-that-runs-entirely-in-your-browser-1p5f</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-built-a-privacy-first-face-blurring-tool-that-runs-entirely-in-your-browser-1p5f</guid>
      <description>&lt;p&gt;Every photo you share online might expose more than you intend — faces of your kids, strangers in the background, license plates, addresses on envelopes, watermarks with your name.&lt;/p&gt;

&lt;p&gt;I wanted a tool that:&lt;/p&gt;

&lt;p&gt;Blurs faces automatically&lt;br&gt;
Detects text like license plates and watermarks&lt;br&gt;
Never uploads my photos anywhere&lt;br&gt;
Works on mobile&lt;br&gt;
Is 100% free&lt;br&gt;
Existing tools either upload to a server (no thanks) or require manual editing. So I built BlurIt — a fully client-side face and text blurring app.&lt;/p&gt;

&lt;p&gt;How it works&lt;br&gt;
Face detection uses SSD MobileNet V1 via TensorFlow.js — a multi-scale single-shot detector that catches small, distant, and partial faces even in crowd scenes. I implemented multi-scale quadrant detection (running the model on the full image + 4 overlapping zoomed quadrants) to catch background faces that single-pass detection misses.&lt;/p&gt;

&lt;p&gt;Text detection uses Tesseract.js v7 with image preprocessing (2x upscaling + grayscale + contrast normalization) and multi-PSM detection (PSM 3 for structured text, PSM 1 for rotated/sideways text, PSM 11 for scattered text like watermarks).&lt;/p&gt;

&lt;p&gt;Both models run locally in the browser via WebAssembly — your photos never leave your device. The model weights are self-hosted (same-origin), so there are zero third-party network requests for user data.&lt;/p&gt;

&lt;p&gt;The privacy architecture&lt;br&gt;
text&lt;/p&gt;

&lt;p&gt;User drops photo&lt;br&gt;
       ↓&lt;br&gt;
  Browser decodes (createImageBitmap)&lt;br&gt;
       ↓&lt;br&gt;
  Canvas + ML model (local WASM)&lt;br&gt;
       ↓&lt;br&gt;
  User taps to blur&lt;br&gt;
       ↓&lt;br&gt;
  Canvas renders pixelate/gaussian/black&lt;br&gt;
       ↓&lt;br&gt;
  Download — done&lt;br&gt;
No server. No API. No database. No analytics. No tracking. The only things stored are your theme preference and a one-time terms acceptance in localStorage.&lt;/p&gt;

&lt;p&gt;The UX&lt;br&gt;
I took inspiration from iLoveIMG — minimal, plug-and-play:&lt;/p&gt;

&lt;p&gt;Icon-only sidebar (3 cycle buttons: Tool, Style, Strength)&lt;br&gt;
Tap detected faces/text to toggle blur&lt;br&gt;
Manual brush for anything auto-detect misses&lt;br&gt;
3 blur styles: pixelate, gaussian, black box&lt;br&gt;
3 intensities: light, medium, heavy&lt;br&gt;
Oval + rectangle brush shapes&lt;br&gt;
What I learned&lt;br&gt;
Client-side ML is viable — SSD MobileNet V1 runs in ~2-3 seconds in a real browser. TensorFlow.js + WebGL makes it fast.&lt;br&gt;
Tesseract struggles with photo-embedded text — it's trained on documents, not scene text. Upscaling + grayscale + contrast normalization helps a lot, but it won't match server-side Vision APIs. That's the privacy tradeoff.&lt;br&gt;
Multi-scale detection matters — single-pass face detection misses small background faces. Running on quadrants (2x zoom) catches them.&lt;br&gt;
Web Workers are essential — OCR and ML inference must run off the main thread or the UI freezes.&lt;br&gt;
Try it&lt;br&gt;
BlurIt is live and free: &lt;a href="https://blurit-lime.vercel.app" rel="noopener noreferrer"&gt;https://blurit-lime.vercel.app&lt;/a&gt;&lt;br&gt;
Open source: &lt;a href="https://github.com/JeffreyHamilton6399/blurit" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/blurit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your photos are yours. BlurIt just helps you protect them. 🛡️&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Every link you share has trackers in it (here's how to clean them)</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 28 Jul 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/every-link-you-share-has-trackers-in-it-heres-how-to-clean-them-1j81</link>
      <guid>https://dev.to/jeffrey_hamilton6399/every-link-you-share-has-trackers-in-it-heres-how-to-clean-them-1j81</guid>
      <description>&lt;p&gt;Have you ever copied a link from an email newsletter or an ad and pasted it into a chat? If you look closely at that URL, you'll see a massive tail of tracking parameters: utm_source, fbclid, gclid, mc_cid.&lt;/p&gt;

&lt;p&gt;When you share that link, you're sharing tracking data. You're telling Facebook, Google, or Mailchimp exactly who clicked what, and from where.&lt;/p&gt;

&lt;p&gt;So I built LinkClean — it strips all tracking parameters from URLs instantly. No sign-up, no tracking, works entirely in your browser.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://linkclean-seven.vercel.app" rel="noopener noreferrer"&gt;https://linkclean-seven.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/linkclean" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/linkclean&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it works&lt;br&gt;
Paste a URL (or a batch of URLs, one per line)&lt;br&gt;
See the clean URL instantly&lt;br&gt;
See what was removed — LinkClean tells you exactly which trackers it stripped&lt;br&gt;
Copy the clean link with one click&lt;br&gt;
It strips 40+ tracking parameters including:&lt;/p&gt;

&lt;p&gt;Google: utm_source, utm_medium, utm_campaign, utm_term, utm_content&lt;br&gt;
Facebook: fbclid, fb_action_ids, fb_ref&lt;br&gt;
Google Ads: gclid, gclsrc, dclid&lt;br&gt;
Mailchimp: mc_cid, mc_eid&lt;br&gt;
Microsoft: msclkid&lt;br&gt;
Amazon: tag, linkCode, linkId, camp&lt;br&gt;
...and many more&lt;br&gt;
The architecture&lt;br&gt;
Zero backend. It's a static site hosted on Vercel. The URL cleaning happens entirely in your browser using the native JavaScript URL API.&lt;/p&gt;

&lt;p&gt;All computation is synchronous (instant results)&lt;br&gt;
Zero dependencies (the app is tiny)&lt;br&gt;
Batch mode: clean 100+ URLs instantly&lt;br&gt;
No tracking, no analytics, no ads&lt;br&gt;
The privacy model&lt;br&gt;
 100% client-side — URLs never leave your browser&lt;br&gt;
 Zero network requests&lt;br&gt;
 No accounts, no tracking, no analytics&lt;br&gt;
 Open source — read every line of code&lt;br&gt;
Try it&lt;br&gt;
 Live: &lt;a href="https://linkclean-seven.vercel.app" rel="noopener noreferrer"&gt;https://linkclean-seven.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/linkclean" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/linkclean&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Stop sharing tracking data when you share links.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>privacy</category>
    </item>
    <item>
      <title>Every photo you share online has hidden GPS data in it (here's how to fix that)</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 21 Jul 2026 14:05:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/every-photo-you-share-online-has-hidden-gps-data-in-it-heres-how-to-fix-that-4c4g</link>
      <guid>https://dev.to/jeffrey_hamilton6399/every-photo-you-share-online-has-hidden-gps-data-in-it-heres-how-to-fix-that-4c4g</guid>
      <description>&lt;p&gt;Every time you take a photo with your phone, it bakes invisible data into the file. This includes:&lt;/p&gt;

&lt;p&gt;Your exact GPS coordinates (accurate to a few meters)&lt;br&gt;
Your phone model and settings&lt;br&gt;
The exact date and time&lt;br&gt;
Sometimes your name and copyright info&lt;br&gt;
When you post that photo to social media, a forum, or a listing, you're sharing all of that data with the world. Stalkers, doxxers, and data brokers exploit this constantly.&lt;/p&gt;

&lt;p&gt;So I built ExifErase — it strips all hidden metadata from your photos before you share them. No uploads, no sign-up, 100% free.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://exif-erase.vercel.app" rel="noopener noreferrer"&gt;https://exif-erase.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/ExifErase" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/ExifErase&lt;/a&gt;&lt;br&gt;
How it works&lt;br&gt;
Drop a photo (JPEG, PNG, WebP, HEIC from iPhone)&lt;br&gt;
See what's hiding — ExifErase shows you the exact GPS, camera, and date data embedded in the file&lt;br&gt;
Erase it — one click strips all metadata&lt;br&gt;
Download the clean photo&lt;br&gt;
The best part: the stripping happens via the Canvas API. When you re-encode an image to a canvas, the metadata simply doesn't carry over. Your file comes out completely clean.&lt;/p&gt;

&lt;p&gt;The privacy model&lt;br&gt;
 100% client-side — photos are processed in your browser&lt;br&gt;
 Zero network requests — your photos never leave your device&lt;br&gt;
 No accounts, no tracking, no analytics&lt;br&gt;
 Open source — read every line of code&lt;br&gt;
Why this matters&lt;br&gt;
If you post a photo of your house, your kid, or your car online, you're also posting a map to your location. ExifErase makes sure that doesn't happen.&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
 Live: &lt;a href="https://exif-erase.vercel.app" rel="noopener noreferrer"&gt;https://exif-erase.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/ExifErase" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/ExifErase&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your photos are yours. The data inside them shouldn't be shared without your knowledge.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>privacy</category>
      <category>showdev</category>
      <category>security</category>
    </item>
    <item>
      <title>I got tired of 15 ad-filled dev tool websites, so I built one clean page</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 14 Jul 2026 14:00:00 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-got-tired-of-15-ad-filled-dev-tool-websites-so-i-built-one-clean-page-2172</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-got-tired-of-15-ad-filled-dev-tool-websites-so-i-built-one-clean-page-2172</guid>
      <description>&lt;p&gt;Every time I need to format JSON, decode a JWT, or generate a UUID, I end up on a different sketchy, ad-heavy website. I got tired of closing popups just to format my code.&lt;/p&gt;

&lt;p&gt;So I built DevToys — 40 essential developer tools in one clean, fast, single page. No ads, no sign-up, no tracking.&lt;/p&gt;

&lt;p&gt;🔗 Try it: &lt;a href="https://devtoys-nu.vercel.app" rel="noopener noreferrer"&gt;https://devtoys-nu.vercel.app&lt;/a&gt;&lt;br&gt;
📦 Source: &lt;a href="https://github.com/JeffreyHamilton6399/devtoys" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/devtoys&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What's inside&lt;br&gt;
40 tools including:&lt;/p&gt;

&lt;p&gt;JSON Formatter — pretty/minify/validate&lt;br&gt;
Base64 — encode/decode&lt;br&gt;
JWT Decoder — header, payload, signature&lt;br&gt;
Regex Tester — live match highlighting&lt;br&gt;
UUID Generator — batch generation&lt;br&gt;
Hash Generator — MD5, SHA-1, SHA-256, SHA-512&lt;br&gt;
Color Converter — HEX ↔ RGB ↔ HSL&lt;br&gt;
Timestamp Converter — Unix ↔ human date&lt;br&gt;
Cron Parser — human-readable schedule&lt;br&gt;
Diff Checker — line-by-line comparison&lt;br&gt;
...and 30 more (URL encoder, Lorem Ipsum, etc.)&lt;br&gt;
The architecture&lt;br&gt;
Zero backend. It's a static site hosted on Vercel. Every tool runs entirely in your browser using native JavaScript APIs.&lt;/p&gt;

&lt;p&gt;All computation is synchronous (instant results)&lt;br&gt;
Zero heavy dependencies (tiny bundle, loads immediately)&lt;br&gt;
No tracking, no analytics, no ads&lt;br&gt;
Mobile responsive&lt;br&gt;
Try it&lt;br&gt;
🔗 Live: &lt;a href="https://devtoys-nu.vercel.app" rel="noopener noreferrer"&gt;https://devtoys-nu.vercel.app&lt;/a&gt;&lt;br&gt;
📦 Source: &lt;a href="https://github.com/JeffreyHamilton6399/devtoys" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/devtoys&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bookmark it and never look for a dev tool website again.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a background remover that doesn't upload your photos (no $40/month)</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Tue, 07 Jul 2026 19:21:49 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-built-a-background-remover-that-doesnt-upload-your-photos-no-40month-ofd</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-built-a-background-remover-that-doesnt-upload-your-photos-no-40month-ofd</guid>
      <description>&lt;p&gt;Remove.bg is a great tool, but it has a problem: they upload your photos to their servers. For personal photos, product images, or sensitive pictures, that's not ideal.&lt;/p&gt;

&lt;p&gt;So I built Cutout — an AI background remover that runs entirely in your browser. No backend, no uploads, no sign-up, no $40/month subscription.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://cutout-murex.vercel.app" rel="noopener noreferrer"&gt;https://cutout-murex.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/Cutout" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/Cutout&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;How it works&lt;br&gt;
The app uses &lt;a class="mentioned-user" href="https://dev.to/imgly"&gt;@imgly&lt;/a&gt;/background-removal, a powerful AI library that runs directly in the browser via WebAssembly.&lt;/p&gt;

&lt;p&gt;When you drop an image:&lt;/p&gt;

&lt;p&gt;The AI model downloads (one-time, ~40MB, then cached by the browser)&lt;br&gt;
The model runs locally via WebGPU/WASM to segment the foreground&lt;br&gt;
The background is removed, leaving a transparent PNG&lt;br&gt;
You download the result&lt;br&gt;
Your photo literally never leaves your device. There is no server.&lt;/p&gt;

&lt;p&gt;Features&lt;br&gt;
Instant removal: Drop a photo, get a transparent PNG in seconds.&lt;br&gt;
Batch mode: Remove backgrounds from multiple images at once.&lt;br&gt;
Background replacement: Keep it transparent, or add a solid white/black background for JPEG export.&lt;br&gt;
Manual refine: If the AI isn't perfect, use the eraser/restore brush to clean up edges.&lt;br&gt;
The privacy model&lt;br&gt;
 100% client-side — photos are processed in your browser&lt;br&gt;
 Zero network requests during processing (except the one-time model download)&lt;br&gt;
 No accounts, no tracking, no analytics&lt;br&gt;
 No server-side storage — there IS no server&lt;br&gt;
 Open source — read every line of code&lt;br&gt;
Try it&lt;br&gt;
 Live: &lt;a href="https://cutout-murex.vercel.app" rel="noopener noreferrer"&gt;https://cutout-murex.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/Cutout" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/Cutout&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — happy to answer questions about the WASM model or the architecture.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>privacy</category>
      <category>ai</category>
    </item>
    <item>
      <title>File converter that never uploads your files?</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Fri, 26 Jun 2026 17:13:59 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/file-converter-that-never-uploads-your-files-1f3</link>
      <guid>https://dev.to/jeffrey_hamilton6399/file-converter-that-never-uploads-your-files-1f3</guid>
      <description>&lt;p&gt;Every online file converter — from Zamzar to CloudConvert to FreeConvert — does the same thing: they upload your files to their servers, convert them, and send them back.&lt;/p&gt;

&lt;p&gt;For personal photos, videos, and sensitive documents, that's not great.&lt;/p&gt;

&lt;p&gt;So I built ConvertIt — a file format converter that runs entirely in your browser. No backend, no uploads, no sign-up.&lt;/p&gt;

&lt;p&gt;What it converts&lt;br&gt;
Images: PNG ↔ JPEG ↔ WebP ↔ AVIF, HEIC → anything, GIF → video&lt;br&gt;
Video: MP4 ↔ WebM, MOV → MP4, any video → extract audio&lt;br&gt;
Audio: WAV → MP3, FLAC → MP3, M4A → MP3, any audio → MP3&lt;br&gt;
Documents: PDF → images (PNG/JPEG), images → PDF, SVG → PNG&lt;br&gt;
How it works&lt;br&gt;
File type   Engine  How&lt;br&gt;
Video   ffmpeg.wasm Compiled to WebAssembly, runs in-browser&lt;br&gt;
Images  Canvas API + OffscreenCanvas    Re-encode to target format&lt;br&gt;
Audio   Web Audio API + lamejs  Decode → re-encode to MP3&lt;br&gt;
PDF pdf-lib + pdfjs-dist    Render pages or combine images&lt;br&gt;
The architecture&lt;br&gt;
Zero backend. It's a static site hosted on Vercel. There is no server — your files are processed entirely in the browser.&lt;/p&gt;

&lt;p&gt;Browser (your device)&lt;br&gt;
├── Drop file&lt;br&gt;
├── Auto-detect input format&lt;br&gt;
├── Show available output formats&lt;br&gt;
├── Convert entirely in memory (Blob URLs)&lt;br&gt;
└── Download result&lt;br&gt;
↳ Files NEVER touch a server&lt;/p&gt;

&lt;h3&gt;
  
  
  Key technical decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;1. Lazy-loaded heavy dependencies&lt;/strong&gt;&lt;br&gt;
ffmpeg.wasm is 32MB. We don't load it until you actually convert a video. Same for pdf-lib (PDFs) and heic2any (iPhone photos). Initial page load stays fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Auto-detection &amp;amp; routing&lt;/strong&gt;&lt;br&gt;
Drop a file → the app detects the format by extension and MIME type → shows only the relevant output formats. You can't convert a PNG to MP3, so we don't show that option.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Mobile memory safeguards&lt;/strong&gt;&lt;br&gt;
Mobile devices get stricter file size limits (100MB for video vs 500MB on desktop), and ffmpeg is terminated after each conversion to free memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Never return a larger file&lt;/strong&gt;&lt;br&gt;
If a conversion somehow makes a file bigger (rare, but happens), we warn the user but still allow it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The privacy model
&lt;/h2&gt;

&lt;p&gt;This is the whole point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;100% client-side — files are processed in your browser&lt;/li&gt;
&lt;li&gt;Zero network requests during conversion&lt;/li&gt;
&lt;li&gt;No accounts, no tracking, no analytics, no cookies&lt;/li&gt;
&lt;li&gt;No server-side storage — there IS no server&lt;/li&gt;
&lt;li&gt;Open source — read every line of code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Your files are yours. They shouldn't need to visit a server to be converted.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Live:&lt;/strong&gt; &lt;a href="https://convertit.vercel.app" rel="noopener noreferrer"&gt;https://convertit.vercel.app&lt;/a&gt;&lt;br&gt;&lt;br&gt;
 &lt;strong&gt;Source:&lt;/strong&gt; &lt;a href="https://github.com/JeffreyHamilton6399/ConvertIt" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — happy to answer questions about the architecture or the ffmpeg.wasm setup.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>java</category>
      <category>privacy</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I built a file compressor that never uploads your files (ffmpeg.wasm + Canvas + Web Audio)</title>
      <dc:creator>Jeffrey Hamilton</dc:creator>
      <pubDate>Wed, 24 Jun 2026 16:57:12 +0000</pubDate>
      <link>https://dev.to/jeffrey_hamilton6399/i-built-a-file-compressor-that-never-uploads-your-files-ffmpegwasm-canvas-web-audio-43id</link>
      <guid>https://dev.to/jeffrey_hamilton6399/i-built-a-file-compressor-that-never-uploads-your-files-ffmpegwasm-canvas-web-audio-43id</guid>
      <description>&lt;p&gt;I kept using online file compressors and realized they all upload your files to sketchy servers. For tax PDFs, personal photos, and sensitive documents — that didn't feel right.&lt;/p&gt;

&lt;p&gt;So I built ShrinkRay — a file compressor that runs entirely in your browser. No backend, no uploads, no sign-up.&lt;/p&gt;

&lt;p&gt;Try it: &lt;a href="https://shrink-ray.vercel.app" rel="noopener noreferrer"&gt;https://shrink-ray.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: GitHub&lt;/p&gt;

&lt;p&gt;What it compresses&lt;br&gt;
Images: PNG, JPEG, WebP, AVIF, HEIC (iPhone photos), GIF, BMP&lt;br&gt;
Video: MP4, WebM, MOV, MKV, animated GIF (via ffmpeg.wasm)&lt;br&gt;
Audio: MP3, WAV, OGG, M4A, FLAC, OPUS&lt;br&gt;
PDF: Re-renders pages as compressed images&lt;br&gt;
3D Models: GLB, GLTF, STL, OBJ, PLY, FBX — with format conversion via Three.js&lt;br&gt;
SVG: Minification (strips metadata, comments, whitespace)&lt;br&gt;
Text/Code: JSON, HTML, CSS, JS, XML, YAML — minified + gzipped&lt;br&gt;
Anything else: Gzip compression&lt;br&gt;
How it works&lt;br&gt;
File type&lt;br&gt;
Engine&lt;br&gt;
How&lt;br&gt;
Video   ffmpeg.wasm Compiled to WebAssembly, runs in-browser&lt;br&gt;
Images  Canvas API + OffscreenCanvas    Re-encode at chosen quality/format&lt;br&gt;
Audio   Web Audio API + lamejs  Decode → re-encode to MP3&lt;br&gt;
PDF pdf-lib + pdfjs-dist    Render pages → rebuild with compressed images&lt;br&gt;
3D  Three.js    Format conversion (STL→GLB, etc.) + gzip&lt;br&gt;
Text/Code   Native JS + fflate  Minify (strip comments/whitespace) → gzip&lt;/p&gt;

&lt;p&gt;The architecture&lt;br&gt;
Zero backend. It's a static site hosted on Vercel. There is no server — your files are processed entirely in the browser using WebAssembly and Canvas APIs.&lt;/p&gt;

&lt;p&gt;text&lt;/p&gt;

&lt;p&gt;Browser (your device)&lt;br&gt;
├── Drop file&lt;br&gt;
├── Auto-detect type (image/video/audio/pdf/3d/text)&lt;br&gt;
├── Route to correct engine&lt;br&gt;
├── Process entirely in memory (Blob URLs)&lt;br&gt;
└── Download result&lt;br&gt;
    ↳ Files NEVER touch a server&lt;br&gt;
Key technical decisions&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Lazy-loaded heavy dependencies&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;ffmpeg.wasm is 32MB. We don't load it until you actually drop a video. Same for Three.js (3D), heic2any (HEIC photos), and pdfjs (PDFs). Initial page load stays fast.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Multi-threaded ffmpeg when available&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On browsers with SharedArrayBuffer (COOP/COEP headers), ffmpeg uses multiple CPU cores via Web Workers. Falls back to single-threaded automatically.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pre-warm on desktop, skip on mobile&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On desktop, ffmpeg starts loading the moment the page opens (so it's ready when you drop a video). On mobile, we skip this — the 32MB download would freeze low-RAM devices.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Never return a larger file&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If compression makes a file bigger (happens with already-compressed files), we return the original instead. You never download a file larger than what you uploaded.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Mobile memory safeguards&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mobile devices get stricter file size limits (100MB for video vs 500MB on desktop), and ffmpeg is terminated after each conversion to free memory.&lt;/p&gt;

&lt;p&gt;The privacy model&lt;br&gt;
This is the whole point:&lt;/p&gt;

&lt;p&gt;100% client-side — files are processed in your browser&lt;br&gt;
 Zero network requests during compression&lt;br&gt;
 No accounts, no tracking, no analytics, no cookies&lt;br&gt;
 No server-side storage — there IS no server&lt;br&gt;
 Open source — read every line of code&lt;br&gt;
Your files are yours. They shouldn't need to visit a server to be compressed.&lt;/p&gt;

&lt;p&gt;Try it&lt;br&gt;
 Live: &lt;a href="https://shrink-ray.vercel.app" rel="noopener noreferrer"&gt;https://shrink-ray.vercel.app&lt;/a&gt;&lt;br&gt;
 Source: &lt;a href="https://github.com/JeffreyHamilton6399/ShrinkRay" rel="noopener noreferrer"&gt;https://github.com/JeffreyHamilton6399/ShrinkRay&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Feedback welcome — happy to answer questions about the ffmpeg.wasm setup, the 3D conversion pipeline, or the architecture.&lt;/p&gt;

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