<?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: Sambhav Tawar</title>
    <description>The latest articles on DEV Community by Sambhav Tawar (@sambhav_tawar).</description>
    <link>https://dev.to/sambhav_tawar</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%2F3392995%2F1d59644a-8336-4e5c-a45d-28e94f4e0fd1.jpg</url>
      <title>DEV Community: Sambhav Tawar</title>
      <link>https://dev.to/sambhav_tawar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sambhav_tawar"/>
    <language>en</language>
    <item>
      <title>How I Build a Screenshot text Editor</title>
      <dc:creator>Sambhav Tawar</dc:creator>
      <pubDate>Sat, 27 Jun 2026 10:49:20 +0000</pubDate>
      <link>https://dev.to/sambhav_tawar/building-screenshot-editor-online-53l</link>
      <guid>https://dev.to/sambhav_tawar/building-screenshot-editor-online-53l</guid>
      <description>&lt;p&gt;I can't count how many times I've been writing documentation, preparing a tutorial, or submitting a bug report and found myself staring at a screenshot that needed a small fix. A typo in the UI mockup. An API key that has to be blurred, an arrow pointing to the one button nobody seems to notice. Simple things, yet somehow always a hassle.&lt;/p&gt;

&lt;p&gt;The tools I had were either too much or too little. Desktop apps like Photoshop gave me endless layers and filters I didn't need—I just wanted to swap a few words. Free online tools? They came with watermarks, forced sign-ups, or asked me to upload sensitive images to some unknown server. And not a single one of them could do the thing I genuinely craved: replace text inside a screenshot and have it look exactly like the original.&lt;/p&gt;

&lt;h2&gt;
  
  
  The space nobody was filling
&lt;/h2&gt;

&lt;p&gt;Screenshot tools live in a strange, fragmented world. On one side you have heavyweight desktop apps like Snagit and Photoshop powerful, but expensive, install-heavy, and overkill for a quick edit. On the other side, lightweight capture tools like Lightshot or Greenshot let you annotate while you capture, but the moment you save and close, that annotation is baked in. No way to tweak it later.&lt;/p&gt;

&lt;p&gt;Then there’s the web-based middle ground. Most of these tools fall into two camps: simple annotators (arrows, text boxes, cropping) or full-blown photo editors that sort-of-handle screenshots. Neither addresses the specific, frustrating problem of editing existing text inside a screenshot with real visual fidelity.&lt;/p&gt;

&lt;p&gt;That’s exactly where Screenshot Editor Online lives. It’s not a general-purpose photo editor. It’s not yet another capture tool. It’s a screenshot text editor built for that moment when you already have a screenshot, you need to change the words, and you need the result to look seamless.&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Replace text, keep the look&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the whole reason the tool exists. You upload a screenshot. The tool uses OCR to find every text element. Click on a word or phrase, and it analyzes the pixels in that area to estimate the font family, size, color, weight, and style (bold, italic, serif or sans-serif). You type your new text, and it renders with those same properties.&lt;/p&gt;

&lt;p&gt;Some examples: &lt;br&gt;
Before: &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%2Fys3yypjbgtwv3e3c3233.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fys3yypjbgtwv3e3c3233.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;br&gt;
After: &lt;br&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%2Fsr93kuxpk6bleaqdn7l8.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsr93kuxpk6bleaqdn7l8.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;All the annotation tools you expect&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Beyond the text magic, there’s a full annotation toolkit. You can draw arrows and shapes, add highlights, blur or pixelate sensitive stuff (emails, phone numbers, API keys), crop, resize, and scribble with a freehand pen. Everything you need to make a screenshot communicate clearly without leaving the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No friction No catch&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There’s no account to create, no watermark slapped on the output, no artificial edit limits. You drag your image in, do your work, and download the result. It handles PNG, JPG, WEBP, and BMP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Privacy by default&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Everything happens locally in your browser. Your image never leaves your machine. For developers working with internal mockups or customer data, that’s not a luxury it’s a necessity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the hood
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Three core technologies make this possible:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fabric.js&lt;/strong&gt; – gives me an object model on top of the HTML5 canvas, so I can treat shapes, text, and images as moveable, editable objects without losing my mind.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tesseract.js&lt;/strong&gt; – a browser-based port of the Tesseract OCR engine. It handles text detection entirely client-side, so there’s no need for a server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vanilla JavaScript&lt;/strong&gt; – no frameworks, no dependencies beyond what’s essential. Plain HTML, CSS, and JS keep things fast and the bundle tiny.&lt;/p&gt;

&lt;h2&gt;
  
  
  The really tough bit: matching fonts
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Tesseract.js tells me where text lives and what it thinks it says, but it doesn’t whisper a word about the font. I had to build custom logic that:&lt;/li&gt;
&lt;li&gt;Upscales the image 3x before OCR – a simple trick that dramatically improves recognition of small text.&lt;/li&gt;
&lt;li&gt;Uses page segmentation mode 11 (sparse text) to pick up words even in complex, non-linear layouts.&lt;/li&gt;
&lt;li&gt;Filters out low-confidence detections – anything below 15% confidence gets tossed so you’re not editing nonsense.&lt;/li&gt;
&lt;li&gt;Analyzes the pixels inside each text bounding box to estimate visual traits: stroke width (bold), slant (italic), and whether the font has serifs.&lt;/li&gt;
&lt;li&gt;Pulls the dominant color straight from the text region for perfect color matching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The trade-offs of local OCR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Keeping everything in the browser is a privacy win, but it’s not free. Tesseract.js is slower than a cloud service, and its accuracy isn’t quite as high. The 3x upscale helps a lot, but it adds processing time. For clean, readable UI screenshots—the vast majority of real-world use cases—the results are solid and fast enough.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why build this now?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The technical pieces have been around for years. Tesseract.js has been available since 2018. Fabric.js even longer. So why hasn’t this tool existed before?&lt;/p&gt;

&lt;p&gt;Two reasons. First, combining robust in-browser OCR with on-the-fly font matching is surprisingly tricky—most developers naturally reach for a server to do the heavy lifting. Second, the established players have been desktop apps or subscription-based SaaS products. The idea of a free, browser-first tool that obsesses over text replacement as the primary feature simply hadn’t found its champion yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I learned along the way&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;OCR isn’t magic, Tesseract.js does a great job on clean, high-contrast text, but stylized fonts, low-res images, and messy backgrounds still trip it up. Upscaling helps, but it’s not a cure-all.&lt;/p&gt;

&lt;p&gt;Font estimation is guesswork dressed in math. You can spot bold or italic from pixels. You cannot reliably distinguish Arial from Helvetica from Open Sans without a much larger contextual model. So, I focused on what matters: reproducing the visual weight, size, color, and slant. The exact font name is a nice-to-have; the visual match is a must.&lt;/p&gt;

&lt;p&gt;Perceived performance matters, OCR on a chunky image can take several seconds. If users don’t see that something is happening, they assume the tool is broken. Keeping the UI responsive and communicative during processing was non-negotiable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where it fits in the market&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Screenshot Editor Online isn’t trying to replace Snagit or CleanShot X—those are paid desktop tools with broader feature sets. It’s not competing with Canva or Fotor either; those are general-purpose design platforms.&lt;/p&gt;

&lt;p&gt;Its real neighbors are other free web-based screenshot editors. But those tools are either annotation-only (no text editing), marred by watermarks, or require uploading your image to a server you know nothing about.&lt;/p&gt;

&lt;p&gt;Our differentiators are clear and intentionally simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Text replacement with font matching&lt;/strong&gt; – no other free tool does this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fully client-side&lt;/strong&gt; – your image stays yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No watermarks, no caps&lt;/strong&gt; – free means free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No account needed&lt;/strong&gt; – zero friction from the second you land on the page.&lt;/p&gt;

&lt;p&gt;The people who care most? Developers, designers, technical writers, support engineers—anyone who lives in a world of screenshots and needs them to be right.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s coming next
&lt;/h2&gt;

&lt;p&gt;The tool is live and starting to find its audience. There’s plenty left to do:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sharper font detection&lt;/strong&gt; – I’m continuing to refine how I estimate style, especially for tricky typefaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;More export options&lt;/strong&gt; – custom resolutions, additional formats.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keyboard shortcuts&lt;/strong&gt; – because power users deserve speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch processing&lt;/strong&gt; – edit multiple screenshots in one session without starting from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Screenshot Editor Online started the way a lot of side projects do: I was frustrated, and the thing I needed didn’t exist. Building it taught me a ton about OCR, canvas manipulation, and the quiet complexity of making something feel simple.&lt;/p&gt;

&lt;p&gt;It’s free, it’s open-source, and it solves a real, everyday headache. If you’ve ever spent twenty minutes in Photoshop trying to match a font in a screenshot, you already know exactly why it’s here.&lt;/p&gt;

&lt;p&gt;Give it a try at &lt;a href="https://screenshoteditoronline.com/" rel="noopener noreferrer"&gt;screenshoteditoronline.com&lt;/a&gt;. No account, no watermark, no limits. Just upload, edit, and download.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>javascript</category>
      <category>security</category>
      <category>software</category>
    </item>
    <item>
      <title>I Built a Subway Nutrition Calculator</title>
      <dc:creator>Sambhav Tawar</dc:creator>
      <pubDate>Sat, 04 Apr 2026 09:16:17 +0000</pubDate>
      <link>https://dev.to/sambhav_tawar/i-built-a-subway-nutrition-calculator-1108</link>
      <guid>https://dev.to/sambhav_tawar/i-built-a-subway-nutrition-calculator-1108</guid>
      <description>&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%2Fb4kq90vy6tbkmcbq7dns.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%2Fb4kq90vy6tbkmcbq7dns.png" alt=" " width="800" height="312"&gt;&lt;/a&gt;&lt;br&gt;
A few months ago, I got tired of clicking through Subway’s website to figure out what I was actually eating. Their PDFs are fine if you want to look up one thing. But if you want to build a custom sandwich—add this bread, skip that cheese, double the chicken, then see how it fits into your daily calories good luck.&lt;/p&gt;

&lt;p&gt;So, I built this &lt;a href="https://subway-calorie-calculator.com/" rel="noopener noreferrer"&gt;calorie calculator&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Not a fancy app with a backend. Just a single HTML file with a ton of JavaScript, a massive JSON‑like data structure, and a stubborn refusal to let a bad UI ruin my lunch.&lt;/p&gt;

&lt;p&gt;I’m going to walk you through how I built it, what broke along the way, and what I’d do differently next time.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;You’d have to manually add bread calories + meat calories + veggie calories (most are zero, but olives and avocado aren’t) + sauce calories. Then double it for footlong. Then remember that cheese adds fat and sodium. Then realize you forgot the salt and pepper.&lt;/p&gt;

&lt;p&gt;It’s tedious and error‑prone. And it’s exactly the kind of problem a simple web tool can solve.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Collecting the Data
&lt;/h2&gt;

&lt;p&gt;I needed a complete, consistent dataset. Every bread, every protein, every cheese, vegetable, condiment, seasoning, side, soup, dessert, and pre‑made sandwich. Plus, salads, wraps, protein pockets, and No Bready Bowls.&lt;/p&gt;

&lt;p&gt;I started with Subway’s official US &lt;a href="https://www.subway.com/en-us/-/media/northamerica/usa/nutrition/nutritiondocuments/2026/us_nutrition_en_1-2026.pdf" rel="noopener noreferrer"&gt;nutrition PDF&lt;/a&gt; (2026 version). Then I cross‑referenced with their online menu, third‑party aggregators, and even some store‑level ingredient sheets.&lt;/p&gt;

&lt;p&gt;Total items ended up at around 300+.&lt;br&gt;
Here’s the rough breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Breads: 12&lt;/li&gt;
&lt;li&gt;Pre‑made sandwiches: 30+&lt;/li&gt;
&lt;li&gt;Proteins (a la carte): 20+&lt;/li&gt;
&lt;li&gt;Cheeses: 5&lt;/li&gt;
&lt;li&gt;Vegetables: 15&lt;/li&gt;
&lt;li&gt;Condiments: 25+ (each with Normal and Light versions)&lt;/li&gt;
&lt;li&gt;Seasonings: 3&lt;/li&gt;
&lt;li&gt;Sides: 2&lt;/li&gt;
&lt;li&gt;Salads: 25+&lt;/li&gt;
&lt;li&gt;Wraps: 25+&lt;/li&gt;
&lt;li&gt;No Bready Bowls: 25+&lt;/li&gt;
&lt;li&gt;Protein Pockets: 4&lt;/li&gt;
&lt;li&gt;Soups: 3&lt;/li&gt;
&lt;li&gt;Desserts: 7&lt;/li&gt;
&lt;li&gt;Sidekicks: 8
Each item needed the same set of nutrition fields:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Calories, total fat, saturated fat, trans fat, cholesterol, sodium, Total carbs, dietary fiber, sugars, added sugars, Protein, Vitamin A (mcg), Vitamin C (mg), Calcium (mg), Iron (mg).&lt;/p&gt;

&lt;p&gt;I also tracked serving size in grams where available, though that’s mostly for reference.&lt;/p&gt;

&lt;p&gt;What I learned: Never trust a single source. Cross‑reference everything and if you’re building a public tool, be transparent about where the data comes from and what’s estimated.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2: Structuring the Data – The JavaScript Object That Runs Everything
&lt;/h2&gt;

&lt;p&gt;I built one massive JavaScript object called subwayMenu. It has arrays for each category: breads, proteins, cheeses, vegetables, condiments, etc.&lt;/p&gt;

&lt;p&gt;Here’s what a single bread item looks like:&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="nx"&gt;javascript&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;artisan-italian-bread-6inch&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;6" Artisan Italian Bread&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;servingSize_g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;71&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;calories&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;210&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;totalFat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;saturatedFat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;transFat&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;cholesterol&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;sodium&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;380&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;totalCarbs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;39&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;dietaryFiber&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;sugars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;addedSugars&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;protein&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;vitaminA_mcg&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;vitaminC_mg&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;calcium_mg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1040&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;iron_mg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;16.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;category&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bread&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;Every item follows the same structure. That’s critical because later I loop through these objects to calculate totals, display values, and filter by search.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The size multiplier logic:&lt;/strong&gt;&lt;br&gt;
For sandwiches, users can choose 6‑inch or footlong. The calculator multiplies bread, proteins, cheeses, vegetables, condiments, and seasonings by 2 when footlong is selected. Pre‑made sandwiches, salads, wraps, and bowls are already sized – they don’t get multiplied again. That logic lives in the calculateTotalNutrition function, where I check a sizeAffected flag for each category.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The quantity system:&lt;/strong&gt;&lt;br&gt;
Users can add multiple of the same item (e.g., double meat, extra cheese). I store quantities in a separate currentSelection object. For each category, it’s a dictionary mapping item IDs to integers. Zero means not selected.`&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;javascript&lt;br&gt;
let currentSelection = {&lt;br&gt;
    sandwichSize: '6inch',&lt;br&gt;
    bread: null,&lt;br&gt;
    proteins: {},&lt;br&gt;
    cheeses: {},&lt;br&gt;
    vegetables: {},&lt;br&gt;
    condiments: {},&lt;br&gt;
    // ... etc&lt;br&gt;
};&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;br&gt;
This structure makes it easy to add, remove, or adjust quantities without rebuilding the whole UI from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: The UI – Dropdowns, Tabs, and a Whole Lot of Dynamic Rendering
&lt;/h2&gt;

&lt;p&gt;I wanted the interface to be clean but powerful. No external libraries just plain HTML, CSS, and vanilla JavaScript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The layout:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Left side: Builder with collapsible categories (Bread, Proteins, Cheeses, etc.) and a tab switcher for different menu types (Sandwich, Salads, Wraps, etc.)&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%2F7w19lj2mp888p6qrpi3b.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%2F7w19lj2mp888p6qrpi3b.png" alt=" " width="646" height="567"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right side: Results section with a nutrition label, calorie progress bar, current selection list, and action buttons.&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%2F4fhparzpjh2gphaa37kz.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%2F4fhparzpjh2gphaa37kz.png" alt=" " width="415" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tab system:&lt;/strong&gt;&lt;br&gt;
On mobile, tabs become a dropdown toggle. On desktop, they could have been buttons, but I kept the dropdown consistent across all devices to simplify CSS. The active tab determines which set of categories (sandwich builder vs. pre‑made salads vs. wraps) is visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collapsible categories:&lt;/strong&gt;&lt;br&gt;
Each category (e.g., “Proteins”) is a &lt;/p&gt; with a header that toggles the content. I used a simple onclick handler (subwayToggleDropdown) that adds/removes an expanded class and rotates an SVG arrow.

&lt;p&gt;&lt;strong&gt;Search inside categories:&lt;/strong&gt;&lt;br&gt;
Every category has a search input that filters items client‑side. No backend calls. The subwaySearchCategory function reads the input, filters the items array, and calls populateCategory to re‑render only that section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The item list:&lt;/strong&gt;&lt;br&gt;
Each item is rendered as a row with a checkbox (or radio for bread), name, calories, and quantity controls (plus/minus buttons). The quantity buttons call subwayAdjustQuantity, which updates the currentSelection object and re‑renders the category and the current selection list.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why re‑render instead of DOM manipulation?&lt;/strong&gt;&lt;br&gt;
Because it’s simpler, I rebuild the category HTML every time something changes. For a category with 20 items, that’s fine. For the whole page, I’d need to be more careful. But here, re‑rendering is fast enough that users don’t notice a delay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: The Nutrition Calculation
&lt;/h2&gt;

&lt;p&gt;The calculateTotalNutrition function is the heart of the tool.&lt;/p&gt;

&lt;p&gt;It does four things:&lt;/p&gt;

&lt;p&gt;Initializes a totals object with zeros for every nutrition field.&lt;/p&gt;

&lt;p&gt;Applies the size multiplier (2 for footlong) to categories that scale with sandwich size.&lt;/p&gt;

&lt;p&gt;Loops through every selected category – bread, proteins, cheeses, vegetables, condiments, etc. And adds the item’s nutrition multiplied by quantity and multiplier.&lt;/p&gt;

&lt;p&gt;Returns the final totals and a list of ingredients (for the ingredients section).&lt;/p&gt;

&lt;p&gt;The math is straightforward addition. No fancy rounding until the end, where I round to one decimal place to keep the display clean.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tricky part:&lt;/strong&gt;&lt;br&gt;
Some items have tiny values (e.g., 0.5g fiber). When you multiply by quantity and size, you get fractions. I store everything as numbers and only round when displaying. That keeps internal calculations accurate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The FDA daily values:&lt;/strong&gt;&lt;br&gt;
I hardcoded a fdaDailyValues object based on a 2,000‑calorie diet. The nutrition label shows % Daily Value for each nutrient. I calculate that as (nutrient_value / fda_daily_value) * 100. For vitamins and minerals, I use the actual mcg/mg values and compare against the FDA standards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: The Current Selection Panel
&lt;/h2&gt;

&lt;p&gt;One thing I’ve always hated about other calculators: you add items, but you can’t see what you’ve added without scrolling back up.&lt;/p&gt;

&lt;p&gt;So, I added a “Current Selection” panel on the right side (bottom in mobile). It lists every item you’ve chosen, with quantity and calories. And here’s the kicker: each item has a small “X” button that removes it directly from the selection.&lt;/p&gt;

&lt;p&gt;That removal calls subwayRemoveItemFromSelection, which updates the currentSelection object, then re‑renders the affected category (to uncheck the item) and the selection panel itself.&lt;/p&gt;

&lt;p&gt;It’s a small quality‑of‑life feature, but it makes a huge difference when you’re tweaking a meal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 6: The Save Function
&lt;/h2&gt;

&lt;p&gt;I added a “Save Nutrition Data” button that exports everything as a plain text file.&lt;/p&gt;

&lt;p&gt;The subwaySaveNutritionInfo function:&lt;/p&gt;

&lt;p&gt;Calls calculateTotalNutrition to get current totals and ingredients.&lt;/p&gt;

&lt;p&gt;Builds a formatted string with meal details, ingredients, nutrition facts, and daily progress.&lt;/p&gt;

&lt;p&gt;Creates a Blob, generates a download link, and triggers a download.&lt;/p&gt;

&lt;p&gt;Shows a temporary “Saved!” feedback on the button.&lt;/p&gt;

&lt;p&gt;I chose plain text because it’s simple, works everywhere, and users can paste it into a note or spreadsheet. No external dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Broke (And How I Fixed It)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. The bread radio group:&lt;/strong&gt;&lt;br&gt;
Originally, I used radio buttons (only one bread allowed). But dynamically re‑rendering radios with JavaScript and keeping their state was a nightmare. I switched to checkboxes but enforced “only one” in the selection logic. The UI still looks like radios, but under the hood, it’s a checkbox group with manual deselection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The footlong multiplier:&lt;/strong&gt;&lt;br&gt;
At first, I applied the multiplier to everything including pre‑made salads and wraps. That was wrong, Salads and wraps have their own fixed nutrition. I had to add a sizeAffected flag to each category and only multiply bread, proteins, cheeses, vegetables, condiments, and seasonings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Search resetting on item change:&lt;/strong&gt;&lt;br&gt;
Every time a user added or removed an item, the category would re‑render and lose the search term. I fixed that by storing the search term in a variable and re‑applying it after re‑render. The subwaySearchCategory function now caches the filtered results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. The save button not working in some browsers:&lt;/strong&gt;&lt;br&gt;
Some browsers block programmatic clicks on download links. I switched to using a Blob and URL.createObjectURL, which works everywhere. Also added a fallback alert if something fails.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Building this calculator was a lesson in data wrangling, UI design for real‑world users, and the joy of solving your own problem.&lt;/p&gt;

&lt;p&gt;It’s not perfect and the code is a little messy. The data could be more complete, but it works. You can build a custom Subway meal, see exactly what you’re eating, and save it for later.&lt;/p&gt;

&lt;p&gt;If you’re a developer thinking about building a similar tool for another restaurant chain, here’s my advice:&lt;/p&gt;

&lt;p&gt;Start with the data: Clean, consistent data is 80% of the work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build the logic first then the UI:&lt;/strong&gt; Get the calculation engine working in the console before you worry about buttons.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test with real users:&lt;/strong&gt; I handed this to a few friends and watched where they got confused. That’s how I learned about the footlong multiplier bug.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don’t overcomplicate it:&lt;/strong&gt; You don’t need a backend, a database, or a build system. A single HTML file with inline CSS and JS is fine for a tool like this.&lt;/p&gt;

&lt;p&gt;Now, whenever I walk into Subway, I know exactly what I’m ordering. And if I’m not sure, I open this calculator on my phone and build it before I get to the counter.&lt;/p&gt;

&lt;p&gt;That’s the whole point, tools should make your life easier, not harder.&lt;/p&gt;

&lt;p&gt;I hope this walkthrough helps someone else build something useful. And if you just wanted to use the calculator, well, now you know what’s under the hood.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Building a Multi-Scale CGPA Calculator</title>
      <dc:creator>Sambhav Tawar</dc:creator>
      <pubDate>Mon, 28 Jul 2025 05:57:42 +0000</pubDate>
      <link>https://dev.to/sambhav_tawar/building-a-multi-scale-cgpa-calculator-208h</link>
      <guid>https://dev.to/sambhav_tawar/building-a-multi-scale-cgpa-calculator-208h</guid>
      <description>&lt;p&gt;As a developer passionate about creating tools that solve real-world problems, I recently built a comprehensive CGPA (Cumulative Grade Point Average) calculator. This project emerged from my own experience as a student struggling to calculate my academic performance accurately across different grading systems. In this article, I'll walk through the technical implementation, design decisions, and features of this open-source calculator.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Problem Space&lt;/strong&gt;&lt;br&gt;
Academic grading systems vary significantly across institutions. While some universities use a 10-point scale, others use 4-point or 5-point systems. This creates confusion for students who need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calculate their current semester GPA.&lt;/li&gt;
&lt;li&gt;Track cumulative performance (CGPA).&lt;/li&gt;
&lt;li&gt;Convert between different grading scales.&lt;/li&gt;
&lt;li&gt;Understand how specific courses impact their overall average.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Technical Stack
&lt;/h2&gt;

&lt;p&gt;The calculator is built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; Vanilla HTML, CSS, and JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Charts:&lt;/strong&gt; Chart.js for data visualization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Icons:&lt;/strong&gt; Font Awesome for UI elements&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics:&lt;/strong&gt; Google Analytics for usage tracking (non-intrusive)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hosting:&lt;/strong&gt; Static site deployment&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Key Features Implemented
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Multi-Scale Support&lt;/strong&gt;&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%2F3gl0kttn04l06f0kol05.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%2F3gl0kttn04l06f0kol05.png" alt="Multi scale support feature" width="639" height="273"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const gradeOptionsByScale = {
  10: [ 
* grade options */ ],
  4: [ /* grade options */ ],
  5: [ /* grade options */ ]
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The calculator dynamically adjusts its interface based on the selected grading scale (4.0, 5.0, or 10.0), ensuring accurate calculations regardless of the institution's system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. College-Specific Presets&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const colleges = [
  { name: "Delhi University", scale: 10, location: "Delhi" },
  { name: "Ashoka University", scale: 4, location: "Sonipat" },
  // 15+ other institutions
];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By selecting their college, students get automatically configured with the correct grading scale and grade descriptors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Dynamic Course Management&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createCourseCard(index, scale) {
  // Dynamically generates course input fields
}

function addCourse() {
  // Adds new course fields on demand
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interface allows students to add or remove courses as needed, with real-time validation and course count tracking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Visual Data Representation&lt;/strong&gt;&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%2Fvaietcl4n1geir3voshp.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%2Fvaietcl4n1geir3voshp.png" alt="Visual Data Representation" width="658" height="801"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function createGaugeChart(ctx, value, maxScale, title) {
  return new Chart(ctx, {
    type: 'doughnut',
    // Chart configuration
  });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using Chart.js, the calculator displays results through intuitive doughnut charts that visually represent academic performance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Calculation Transparency&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function showCalculationBreakdown() {
  // Generates detailed HTML table showing the math
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A comprehensive breakdown section shows students exactly how their GPA was calculated, building trust through transparency.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Responsive Design&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@media (max-width: 768px) {
  /* Mobile-specific styles */
  .course-grid {
    grid-template-columns: 1fr;
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The calculator works seamlessly on all devices using CSS Grid, Flexbox, and responsive design principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Technical Challenges and Solutions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Challenge 1: Dynamic Form Generation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Generating course inputs dynamically while maintaining state was tricky. I solved this by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a template-based card generation system&lt;/li&gt;
&lt;li&gt;Using event delegation for efficient handling&lt;/li&gt;
&lt;li&gt;Storing state in DOM elements with data attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenge 2: Cross-Scale Calculations&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function calculateCGPA() {
  // Handles different scales and conversions
  const currentScale = parseInt(cgpaScale.value) || 10;
  // Calculation logic
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The algorithm needed to handle:&lt;/li&gt;
&lt;li&gt;Different grading scales&lt;/li&gt;
&lt;li&gt;Previous CGPA integration&lt;/li&gt;
&lt;li&gt;Credit-weighted calculations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The solution was a flexible calculation function that normalizes all inputs to a common base.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge 3: Responsive Data Tables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.table-responsive {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the detailed breakdown tables, I implemented horizontal scrolling containers that work smoothly on mobile devices while maintaining readability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge 4: Performance Optimization&lt;/strong&gt;&lt;br&gt;
To ensure smooth performance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chart instances are properly destroyed before recreation&lt;/li&gt;
&lt;li&gt;DOM operations are minimized through batch updates&lt;/li&gt;
&lt;li&gt;Event listeners are delegated where possible&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  User Experience Considerations
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Progressive Disclosure:&lt;/strong&gt; Advanced options (previous CGPA) are available but don't clutter the main interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visual Feedback:&lt;/strong&gt; Animations and color-coded results help users understand their performance at a glance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Educational Content:&lt;/strong&gt; Integrated articles explain grading systems to help students understand the calculations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error Prevention:&lt;/strong&gt; Real-time validation prevents invalid inputs and provides helpful messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;project/
├── index.html
├── style.css
└── script.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application follows a simple yet effective structure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTML:&lt;/strong&gt; Semantic markup with proper ARIA attributes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS:&lt;/strong&gt; Modular design with CSS variables for theming.
3.&lt;strong&gt;JavaScript:&lt;/strong&gt; Modular functions with clear separation of concerns.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Building this CGPA calculator was a rewarding experience that combined technical challenges with practical utility. The project demonstrates how vanilla web technologies can create powerful, accessible tools without heavy frameworks.&lt;/p&gt;

&lt;p&gt;The complete tool is available on our &lt;a href="https://cgpacalculator.in/" rel="noopener noreferrer"&gt;site&lt;/a&gt; for anyone who wants to examine and test the tool.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
