<?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: Mehdi Tareghi</title>
    <description>The latest articles on DEV Community by Mehdi Tareghi (@mehditareghi).</description>
    <link>https://dev.to/mehditareghi</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%2F1344674%2Fed47cd66-f1ab-4288-a52f-1cf55532cc27.png</url>
      <title>DEV Community: Mehdi Tareghi</title>
      <link>https://dev.to/mehditareghi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mehditareghi"/>
    <language>en</language>
    <item>
      <title>I wanted Squoosh with batch and a KB budget, so I built a client-side compressor</title>
      <dc:creator>Mehdi Tareghi</dc:creator>
      <pubDate>Mon, 31 Aug 2026 17:35:06 +0000</pubDate>
      <link>https://dev.to/mehditareghi/i-wanted-squoosh-with-batch-and-a-kb-budget-so-i-built-a-client-side-compressor-39in</link>
      <guid>https://dev.to/mehditareghi/i-wanted-squoosh-with-batch-and-a-kb-budget-so-i-built-a-client-side-compressor-39in</guid>
      <description>&lt;p&gt;I compress images for websites, side projects, and client work. For years that meant TinyPNG or &lt;a href="https://squoosh.app" rel="noopener noreferrer"&gt;Squoosh&lt;/a&gt;. Neither matched how I actually work.&lt;/p&gt;

&lt;p&gt;TinyPNG is fast and familiar. It also wants the file. You upload. The free web tool caps you at 20 images per session and 5 MB each. After that you pay, wait, or split a folder into batches of twenty. The compression is fine. The trust model is “someone else’s server, hope they delete it.” I did not want that for client photos, UI screenshots, or anything I would not put on a public CDN first.&lt;/p&gt;

&lt;p&gt;Squoosh is the other extreme, and I still use it for one picture. Drop a file, pick MozJPEG / WebP / AVIF / JXL / Oxipng, compare sides, download. The image never leaves the browser. That part is right. The workflow is not: one file at a time, no folder drop, no ZIP, no “make this under 100 KB.” The CLI and library were deprecated years ago. The web app still works; it is not where I go when a &lt;code&gt;public/images&lt;/code&gt; folder lands on my desk.&lt;/p&gt;

&lt;p&gt;I am Mehdi Tareghi. I build software from Iran. I got tired of the gap and built &lt;a href="https://assetmelt.com/studio" rel="noopener noreferrer"&gt;Asset Melt&lt;/a&gt;: Squoosh-grade WASM codecs, plus the batch and budget pieces I kept missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it does
&lt;/h2&gt;

&lt;p&gt;Studio is a static app. Open it, drop files, encode on your machine, download. No account.&lt;/p&gt;

&lt;p&gt;Codecs run in Web Workers via WebAssembly: &lt;strong&gt;MozJPEG, AVIF, WebP, Oxipng, and JPEG XL&lt;/strong&gt; (plus QOI). HEIC from a camera roll decodes locally with libheif. PNG is lossless Oxipng by default, with optional palette reduction when you want lossy PNG-8.&lt;/p&gt;

&lt;p&gt;The parts I built because Squoosh would not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Batch and folders.&lt;/strong&gt; Drop a directory. Nested images are walked; non-images are skipped. The queue is reorderable. You can add files while a batch is encoding, pause mid-run, and export a ZIP that keeps relative paths (&lt;code&gt;products/a/hero.webp&lt;/code&gt;). There is no 20-image cap. Device memory is the cap.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A KB budget.&lt;/strong&gt; “Quality 75” is not a size. I often need &lt;em&gt;under 50 KB&lt;/em&gt;, &lt;em&gt;under 100 KB&lt;/em&gt;, or &lt;em&gt;under 200 KB&lt;/em&gt; for an OG image, a newsletter hero, or a card. Studio binary-searches quality (and PNG palette size) against that cap for JPEG, WebP, AVIF, and JXL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform kits.&lt;/strong&gt; Fit-to-size presets for OG, X, Instagram, YouTube, favicon, App Store screenshots, and newsletter widths — as ZIPs, not a scavenger hunt through a resize panel.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also export more than one format in a single run (AVIF / WebP / optional JPEG). Recipes live in the URL (&lt;code&gt;?recipe=&lt;/code&gt;); photos do not. Code is at &lt;a href="https://github.com/mehditareghi/assetmelt" rel="noopener noreferrer"&gt;github.com/mehditareghi/assetmelt&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Images stay on the device. The site is not invisible.
&lt;/h2&gt;

&lt;p&gt;Image bytes never upload. There is no image API. I cannot see, store, or recover your files. Close the tab and in-progress work is gone unless you exported. That is architecture, not a footer promise.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;site&lt;/em&gt; still has UI analytics. I use Google Analytics 4 for page views and coarse events (files added, processing finished, export — counts and formats, not filenames or pixels). Sentry gets crashes, traces, and sampled session replay of the website chrome, not your pictures: media is blocked, Studio previews are local blob URLs. Vercel records web vitals. It is all on &lt;a href="https://assetmelt.com/privacy" rel="noopener noreferrer"&gt;assetmelt.com/privacy&lt;/a&gt;. If a privacy pitch hides telemetry, it is a lie. This one does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in about 20 seconds
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;a href="https://assetmelt.com/studio" rel="noopener noreferrer"&gt;assetmelt.com/studio&lt;/a&gt;. No signup.&lt;/li&gt;
&lt;li&gt;Drop a JPEG, a PNG, or a whole folder.&lt;/li&gt;
&lt;li&gt;Pick WebP or AVIF, &lt;strong&gt;or&lt;/strong&gt; turn on a size budget — under 100 KB is a good first test.&lt;/li&gt;
&lt;li&gt;Process (Cmd/Ctrl+Enter).&lt;/li&gt;
&lt;li&gt;Download the file, or ZIP the queue.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you already know the cap, these open Studio with the budget on: &lt;a href="https://assetmelt.com/compress/under-50kb" rel="noopener noreferrer"&gt;under 50 KB&lt;/a&gt;, &lt;a href="https://assetmelt.com/compress/under-100kb" rel="noopener noreferrer"&gt;under 100 KB&lt;/a&gt;, &lt;a href="https://assetmelt.com/compress/under-200kb" rel="noopener noreferrer"&gt;under 200 KB&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;First load pulls WASM modules. After that, work is local CPU. A cheap laptop will feel a large AVIF batch. That is expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Squoosh vs TinyPNG vs Asset Melt
&lt;/h2&gt;

&lt;p&gt;Features only. No invented traffic numbers, no “X% smaller” claims.&lt;/p&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;Squoosh&lt;/th&gt;
&lt;th&gt;TinyPNG (free web)&lt;/th&gt;
&lt;th&gt;Asset Melt&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where encoding runs&lt;/td&gt;
&lt;td&gt;Your browser (WASM)&lt;/td&gt;
&lt;td&gt;Tinify’s servers (upload)&lt;/td&gt;
&lt;td&gt;Your browser (WASM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Account&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Not required for the free web tool&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Batch&lt;/td&gt;
&lt;td&gt;One image at a time&lt;/td&gt;
&lt;td&gt;Up to 20 images / session, 5 MB each&lt;/td&gt;
&lt;td&gt;Folder drop, queue, ZIP; RAM is the limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hit a KB target&lt;/td&gt;
&lt;td&gt;Quality / codec sliders&lt;/td&gt;
&lt;td&gt;Automatic compression, no “under N KB” budget&lt;/td&gt;
&lt;td&gt;Binary-search under 50 / 100 / 200 KB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Codecs / formats&lt;/td&gt;
&lt;td&gt;MozJPEG, WebP, AVIF, JXL, Oxipng, QOI, WP2&lt;/td&gt;
&lt;td&gt;JPEG, PNG, WebP, AVIF&lt;/td&gt;
&lt;td&gt;MozJPEG, WebP, AVIF, Oxipng, JXL, QOI; HEIC decode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Platform kits (OG, X, App Store, …)&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Resize via paid / API, not kit ZIPs&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Open source&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Images uploaded&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Site analytics&lt;/td&gt;
&lt;td&gt;Yes (Google Analytics on the app)&lt;/td&gt;
&lt;td&gt;Yes (it is a hosted service)&lt;/td&gt;
&lt;td&gt;Yes — UI only, disclosed on &lt;code&gt;/privacy&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;TinyPNG is still the right choice if you want a hosted API, a WordPress plugin, or you are fine uploading and staying inside the free 20. Squoosh is still the right choice if you want a side-by-side codec lab for &lt;em&gt;one&lt;/em&gt; file. I use both as references. I built Asset Melt for the days I have a folder, a size cap, and no reason to send pixels off-device.&lt;/p&gt;

&lt;p&gt;I did not write MozJPEG. I wired the same family of engines Squoosh proved in the browser (&lt;code&gt;@jsquash&lt;/code&gt;, libheif) into a React app, then added a queue, a budget search, and the export paths I kept wishing existed. There is no cloud history and no team workspace — there is no backend that receives photos. It is free. No plan page.&lt;/p&gt;

&lt;p&gt;If that is the workflow you already have in your head — batch, a KB number, files that stay put — open &lt;a href="https://assetmelt.com/studio" rel="noopener noreferrer"&gt;the studio&lt;/a&gt; and drop something.&lt;/p&gt;

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