<?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: Aniket Saini</title>
    <description>The latest articles on DEV Community by Aniket Saini (@aniket_saini_7).</description>
    <link>https://dev.to/aniket_saini_7</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%2F4011690%2F24890610-68fa-470d-a419-e75a48be1b27.png</url>
      <title>DEV Community: Aniket Saini</title>
      <link>https://dev.to/aniket_saini_7</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aniket_saini_7"/>
    <language>en</language>
    <item>
      <title>QuietBench: A Free Developer Utility Suite I Built Solo (No Ads, No Sign-Up, No BS)</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Sat, 11 Jul 2026 14:52:09 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/quietbench-a-free-developer-utility-suite-i-built-solo-no-ads-no-sign-up-no-bs-1g5m</link>
      <guid>https://dev.to/aniket_saini_7/quietbench-a-free-developer-utility-suite-i-built-solo-no-ads-no-sign-up-no-bs-1g5m</guid>
      <description>&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;QuietBench (quietbench.dev) is a free suite of everyday developer utilities — the kind of tools you Google at 2am when you're stuck on something small but annoying:&lt;/p&gt;

&lt;p&gt;JSON Formatter — format, validate, and minify JSON instantly&lt;br&gt;
Regex Tester — test patterns with live match highlighting&lt;br&gt;
Cron Builder — build and understand cron expressions without memorizing syntax&lt;br&gt;
WCAG Contrast Checker — check color contrast ratios for accessibility compliance&lt;br&gt;
API Request Tester — send requests and inspect responses without opening Postman&lt;/p&gt;

&lt;p&gt;No accounts. No paywalls. No cookie-consent maze. Just open the tab, do the thing, close the tab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why I Built It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I kept bouncing between five different single-purpose tool sites every time I needed to format JSON or test a regex — each with its own ad-heavy layout, weird UX, and a sign-up wall for "advanced" features I didn't need. I wanted one clean, fast place for the tools I reach for constantly. So I built it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tech Stack&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;React + Vite + TypeScript for the frontend&lt;br&gt;
Tailwind CSS for styling&lt;br&gt;
Cloudflare Pages for hosting&lt;br&gt;
Porkbun for the domain&lt;/p&gt;

&lt;p&gt;The whole thing is a static SPA, deployed with a single command:&lt;/p&gt;

&lt;p&gt;npm run deploy&lt;/p&gt;

&lt;p&gt;which runs the Vite build, prerenders every route, and pushes to Cloudflare via Wrangler.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenges I Ran Into&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A CSP regression that tanked my LCP score&lt;br&gt;
I tightened my Content Security Policy for safety and accidentally forgot to allowlist Google Fonts. Page load time (LCP) spiked overnight. Lesson: every CSP change needs a Lighthouse re-check, not just a "looks fine" glance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;SPAs and crawlers don't get along&lt;br&gt;
Since QuietBench is a client-rendered SPA, non-JS crawlers (and some bots) were seeing an empty shell instead of actual content. I fixed this with build-time prerendering using Playwright — every one of the 11 routes now gets a fully-rendered HTML snapshot generated at build time, so crawlers see real content without needing to execute JS.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Getting indexed without SEO gimmicks&lt;br&gt;
Rather than chasing broad, competitive keywords, I focused on long-tail, exact-match queries — specific error messages, exact syntax terms, the kind of thing someone pastes directly into Google when they're stuck. I also set up IndexNow for instant Bing submission on every deploy, so new content doesn't sit around waiting to be crawled.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The little things that break silently&lt;br&gt;
A www/non-www redirect inconsistency was quietly splitting my traffic and confusing search engines — fixed with a Cloudflare Redirect Rule. Small, boring, but it matters for SEO hygiene.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;What's Next&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Two more long-tail content pages, currently paused while I read Search Console data to make sure I'm building the right pages, not just more pages&lt;br&gt;
Continued distribution — dev.to has been the most genuinely engaged channel so far&lt;br&gt;
More utilities based on what I personally keep needing&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try It&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;👉 quietbench.dev&lt;/p&gt;

&lt;p&gt;It's free, it's fast, and it doesn't ask you for your email. Would genuinely love feedback from other devs — especially if a tool is missing something you'd expect, or if you spot a bug.&lt;/p&gt;

&lt;p&gt;Building this solo, learning SEO and infra as I go. If you're into indie dev tools or want to swap notes on prerendering/IndexNow setups, drop a comment — happy to share specifics.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>RivalryFuel: AI Hype Commentary for Any Rivalry</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Fri, 10 Jul 2026 11:00:06 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/rivalryfuel-ai-hype-commentary-for-any-rivalry-1303</link>
      <guid>https://dev.to/aniket_saini_7/rivalryfuel-ai-hype-commentary-for-any-rivalry-1303</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for &lt;a href="https://dev.to/challenges/weekend-2026-07-09"&gt;Weekend Challenge: Passion Edition&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;RivalryFuel&lt;/strong&gt; — an AI-powered hype commentary generator that turns any rivalry into a dramatic, stadium-announcer-style speech. Pick two sides (sports teams, tech stacks, even Tea vs Coffee), hit generate, and Gemini writes a passionate, biased commentary — then ElevenLabs brings it to life with a real announcer voice.&lt;/p&gt;

&lt;p&gt;With the World Cup happening right now, passion for rivalries is everywhere — in stadiums, group chats, comment sections. RivalryFuel captures that same chaotic, biased energy in a 30-second, shareable format. My goal was to build something that felt genuinely fun to click "generate" on more than once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🔗 &lt;strong&gt;Live App:&lt;/strong&gt; &lt;a href="https://rivalryfuel-686994035117.asia-southeast1.run.app" rel="noopener noreferrer"&gt;https://rivalryfuel-686994035117.asia-southeast1.run.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🎥 &lt;strong&gt;Video Demo:&lt;/strong&gt; &lt;a href="https://youtu.be/imMa8FMHlck" rel="noopener noreferrer"&gt;https://youtu.be/imMa8FMHlck&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try it yourself — click a preset like "Messi vs Ronaldo," hit Generate Commentary, then hit "Listen to Column" to hear it out loud.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;p&gt;The app is built with React + TypeScript + Vite + Tailwind CSS, deployed on Google Cloud Run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gemini 2.0 Flash&lt;/strong&gt; powers the core hype generation — I engineered the prompt to keep responses playful, biased toward the chosen side, and dramatically "shouted into a stadium mic" rather than neutral or robotic. Getting the tone right took a few iterations of prompt tweaking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ElevenLabs&lt;/strong&gt; handles the text-to-speech layer — the generated commentary is sent to ElevenLabs' API and played back in-browser as a stadium-announcer voice, turning static text into something that actually feels alive.&lt;/p&gt;

&lt;p&gt;One fun challenge: I hit Gemini's free-tier rate limit mid-build and had to switch API keys/projects to keep testing — a good reminder that even small demo apps need quota planning. I also had a UI bug where longer names like "Cristiano Ronaldo" were clipping on smaller screens, fixed with responsive flex layouts and dynamic font scaling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;p&gt;Submitting for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🏆 &lt;strong&gt;Best Use of Google AI&lt;/strong&gt; — Gemini 2.0 Flash generates all commentary in real time with custom prompt engineering for tone and bias&lt;/li&gt;
&lt;li&gt;🏆 &lt;strong&gt;Best Use of ElevenLabs&lt;/strong&gt; — Real-time text-to-speech converts generated commentary into an actual audible stadium-announcer moment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thanks for putting together another fun challenge — built this solo over the weekend! Would love to hear what rivalry you'd want to see hyped up next 🔥&lt;/p&gt;

&lt;h1&gt;
  
  
  weekendchallenge
&lt;/h1&gt;

</description>
      <category>devchallenge</category>
      <category>weekendchallenge</category>
      <category>ai</category>
      <category>react</category>
    </item>
    <item>
      <title>What actually happens when you launch a side project with zero audience</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Thu, 09 Jul 2026 03:09:10 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/what-actually-happens-when-you-launch-a-side-project-with-zero-audience-5d7o</link>
      <guid>https://dev.to/aniket_saini_7/what-actually-happens-when-you-launch-a-side-project-with-zero-audience-5d7o</guid>
      <description>&lt;p&gt;Everyone talks about the build. Nobody talks about what happens the week after, when you go to actually tell people it exists and discover every distribution channel has its own quiet gatekeeping you didn't know about until you hit it.&lt;/p&gt;

&lt;p&gt;Hacker News flagged my Show HN before it ever reached the front page. Not rejected — flagged, silently, likely because the account posting it was brand new with a self-promotional link and zero history. No warning, no explanation, just gone from /newest for anyone not specifically looking.&lt;/p&gt;

&lt;p&gt;Reddit was worse in a different way. r/webdev's AutoMod rejects any submission from an account under three months old with low karma — a hard gate, not a soft one, and it doesn't care which day you post or how you phrase it. r/SideProject let the post through technically, but Reddit's own spam filter quietly removed it minutes later, invisible to everyone except me looking at my own profile.&lt;/p&gt;

&lt;p&gt;X was just silence. Zero followers means the algorithm has no graph to push the post into. Four views, three of which were probably me refreshing.&lt;/p&gt;

&lt;p&gt;The one channel that actually worked was the one with the lowest bar to entry: writing. dev.to doesn't gate you behind account age or karma. You write something, it's live, and if it's genuinely useful, people find it — slowly, but for real. That's where actual engagement happened.&lt;/p&gt;

&lt;p&gt;The pattern underneath all of this: almost every high-leverage distribution channel is, by design, hostile to accounts with no history. That's not a bug — it's the exact mechanism that keeps those platforms usable, and it exists specifically to stop people doing exactly what I was trying to do: show up once with a link and leave. The system is working as intended. It just doesn't feel that way when you're the one hitting the wall.&lt;/p&gt;

&lt;p&gt;What's actually working, three weeks in, isn't a growth hack — it's writing things people search for, verbatim, and being patient about everything else building account history the boring way: showing up, commenting on other people's stuff, and not trying to skip the line.&lt;/p&gt;

&lt;p&gt;If you're about to launch something with a brand-new account everywhere, budget for this. It's not a failure state, it's just how the first few weeks go.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Securing Your CI/CD Pipeline from Day One: A Practical Guide</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Wed, 08 Jul 2026 14:39:13 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/securing-your-cicd-pipeline-from-day-one-a-practical-guide-4oak</link>
      <guid>https://dev.to/aniket_saini_7/securing-your-cicd-pipeline-from-day-one-a-practical-guide-4oak</guid>
      <description>&lt;p&gt;**Outline: Securing Your CI/CD Pipeline from Day One&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Introduction: The "Shift-Left" Mindset**
The Hook: Start with a brief explanation of why waiting until production to check for security vulnerabilities is a recipe for disaster.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Solution: Introduce the concept of DevSecOps and "shifting left"—bringing security into the earliest stages of the software development lifecycle.&lt;/p&gt;

&lt;p&gt;What We're Building: Briefly outline the architecture: A Python Flask application, containerized with Docker, moving through a Jenkins pipeline that automatically halts if critical vulnerabilities are detected by Snyk or Trivy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The Prerequisites&lt;/strong&gt;&lt;br&gt;
Provide a quick checklist for readers who want to follow along:&lt;/p&gt;

&lt;p&gt;A basic Python Flask application pushed to a Git repository.&lt;/p&gt;

&lt;p&gt;A working Jenkins server.&lt;/p&gt;

&lt;p&gt;Docker installed on the Jenkins agent.&lt;/p&gt;

&lt;p&gt;A free Snyk account (for the API token) and Trivy installed on the pipeline environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Stage 1: Dependency Scanning with Snyk (SAST)&lt;/strong&gt;&lt;br&gt;
The Concept: Explain that modern apps are mostly made of open-source libraries. Snyk scans the requirements.txt file of the Flask app to find known vulnerabilities (CVEs) in those dependencies.&lt;/p&gt;

&lt;p&gt;Pipeline Integration: Show how to add Snyk into the Jenkinsfile.&lt;/p&gt;

&lt;p&gt;Key Takeaway: Explain the importance of failing the build only on high or critical severity issues to avoid pipeline fatigue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Stage 2: Container Image Scanning with Trivy&lt;/strong&gt;&lt;br&gt;
The Concept: Once the application code passes, it gets built into a Docker image. Trivy steps in here to scan the underlying OS packages and base image (e.g., python:3.9-slim) for vulnerabilities.&lt;/p&gt;

&lt;p&gt;Pipeline Integration: Walk through the shell commands used in Jenkins to trigger Trivy against the newly built local image before it gets pushed to a registry.&lt;/p&gt;

&lt;p&gt;Why Both? Briefly clarify why you need both tools: Snyk for the application layer (Python dependencies) and Trivy for the infrastructure layer (the container itself).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The Jenkinsfile (The Heart of the Article)
Provide a clean, well-commented declarative pipeline snippet. This is what your readers are really here for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Groovy&lt;br&gt;
pipeline {&lt;br&gt;
    agent any&lt;br&gt;
    stages {&lt;br&gt;
        stage('Checkout') {&lt;br&gt;
            // Git checkout steps&lt;br&gt;
        }&lt;br&gt;
        stage('Security Scan: Snyk') {&lt;br&gt;
            // Snyk testing steps for Python&lt;br&gt;
        }&lt;br&gt;
        stage('Build Image') {&lt;br&gt;
            // Docker build steps&lt;br&gt;
        }&lt;br&gt;
        stage('Container Scan: Trivy') {&lt;br&gt;
            // Trivy scanning steps&lt;br&gt;
        }&lt;br&gt;
    }&lt;br&gt;
}&lt;br&gt;
&lt;strong&gt;6. Conclusion &amp;amp; Next Steps&lt;/strong&gt;&lt;br&gt;
Wrap up by summarizing how this automated approach saves time and prevents compromised code from reaching production.&lt;/p&gt;

&lt;p&gt;Encourage readers to try implementing this in their own homelabs or side projects.&lt;/p&gt;

&lt;p&gt;This structure balances theoretical concepts with the practical, code-heavy execution that the DEV Community loves.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>What my first week of Google Search Console data taught me about SEO for a new site</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Tue, 07 Jul 2026 05:34:32 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/what-my-first-week-of-google-search-console-data-taught-me-about-seo-for-a-new-site-4d9i</link>
      <guid>https://dev.to/aniket_saini_7/what-my-first-week-of-google-search-console-data-taught-me-about-seo-for-a-new-site-4d9i</guid>
      <description>&lt;p&gt;I assumed getting indexed was the hard part. It wasn't — Quietbench got crawled and indexed within days. What the first week of impression data actually taught me was something more specific: which kind of page a brand-new domain can realistically rank for, and which it can't yet.&lt;/p&gt;

&lt;p&gt;The main tool pages got zero impressions. /json-formatter, /regex-tester, /api-tester — nothing. Makes sense in hindsight: "JSON formatter" is a query owned by sites with a decade of backlinks and authority. A new domain isn't out-competing that anytime soon, no matter how good the tool is.&lt;/p&gt;

&lt;p&gt;The long-tail supporting pages got almost all of the traction. Pages like /regex-tester/cheat-sheet and /cron-builder/syntax-explained picked up impressions almost immediately, for queries like "cron syntax" and "website contrast checker" — specific, lower-competition phrases with far less entrenched competition.&lt;/p&gt;

&lt;p&gt;The clearest signal came from one page that got zero impressions despite being indexed. I'd written a /api-tester/what-is-cors page targeting the query "what is CORS" — a broad, heavily-answered question already owned by MDN, web.dev, and freeCodeCamp. Meanwhile, the page's own content had the exact console error text buried in a sub-section: "No 'Access-Control-Allow-Origin' header is present...". That's the actual thing someone in a debugging session searches for, verbatim, not a definitional question. Restructuring the page to lead with that error message instead of the broad definition was a one-line insight that took a week of data to actually see.&lt;/p&gt;

&lt;p&gt;The pattern, stated plainly: a new domain can't compete on definitional or generic queries yet, no matter the content quality. It can compete on specific, verbatim, low-competition phrasing almost immediately — error messages, exact syntax terms, comparison phrases. If you're building a new site's content strategy, the frustrating console error your users paste into Google is worth more, right now, than the polished "what is X" page you were probably planning to write first.&lt;/p&gt;

&lt;p&gt;Following that data, not a guess, is doing more for the site's early SEO than anything I planned upfront.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>analytics</category>
      <category>seo</category>
      <category>performance</category>
    </item>
    <item>
      <title>Adding a Content Security Policy to a static SPA without breaking anything</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Mon, 06 Jul 2026 02:59:39 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/adding-a-content-security-policy-to-a-static-spa-without-breaking-anything-2mbm</link>
      <guid>https://dev.to/aniket_saini_7/adding-a-content-security-policy-to-a-static-spa-without-breaking-anything-2mbm</guid>
      <description>&lt;p&gt;Quietbench started from a scaffolded template that shipped with zero security headers. Adding them properly was less about writing the policy and more about not breaking the one tool that needs to stay permissive.&lt;/p&gt;

&lt;p&gt;The easy part: X-Frame-Options: DENY, X-Content-Type-Options: nosniff, and a sane Referrer-Policy — free wins, nothing depends on being frameable.&lt;/p&gt;

&lt;p&gt;The tricky part: the site has an API tester that needs to fetch() arbitrary user-supplied URLs. A locked-down connect-src 'self' would've quietly broken it. Fix was leaving connect-src * intentionally open while keeping everything else tight — script-src 'self', frame-ancestors 'none'. A CSP doesn't need to be uniformly strict, just strict where it matters for your app.&lt;/p&gt;

&lt;p&gt;The gotcha: vite dev doesn't read the _headers file at all, so testing against the regular dev server tells you nothing about whether the CSP will actually apply. Cloudflare Pages reads _headers at deploy time — the only way to test that locally is running the build through wrangler pages dev dist, which mirrors production behavior. Skip that and you're shipping headers you never actually verified.&lt;/p&gt;

&lt;p&gt;Also cleaned up @google/genai and express - leftover scaffold dependencies nothing imported. Not vulnerabilities, just unaudited surface for zero benefit. Dropped 121 packages.&lt;/p&gt;

&lt;p&gt;Live at quietbench.dev if you want to check the headers yourself.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
      <category>javascript</category>
    </item>
    <item>
      <title>What building a contrast checker taught me about WCAG that I had wrong</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Sun, 05 Jul 2026 02:30:23 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/what-building-a-contrast-checker-taught-me-about-wcag-that-i-had-wrong-4947</link>
      <guid>https://dev.to/aniket_saini_7/what-building-a-contrast-checker-taught-me-about-wcag-that-i-had-wrong-4947</guid>
      <description>&lt;p&gt;I assumed the WCAG contrast checker for Quietbench would be the simplest tool in the suite — compute a ratio, compare it to a threshold, done. A few things surprised me enough to change how I think about accessibility in my own projects.&lt;/p&gt;

&lt;p&gt;"Passing AA" isn't one number. The 4.5:1 ratio everyone quotes only applies to normal text. Large text (18pt+, or 14pt+ bold) only needs 3:1. UI components and graphical objects have their own 3:1 threshold under WCAG 2.1's non-text contrast rule. A tool that only checks one ratio against one threshold is giving wrong answers for half the content on a real page.&lt;/p&gt;

&lt;p&gt;AAA isn't just "AA but stricter" in the way I assumed. AAA bumps normal text to 7:1, but the large-text threshold only moves to 4.5:1 — not a flat multiplier. Building the "suggest a fix" feature meant handling these as genuinely different target ratios per content type, not one formula scaled up.&lt;/p&gt;

&lt;p&gt;The relative luminance formula is not intuitive. WCAG doesn't compare RGB values directly — it converts to relative luminance first, which weights green far more heavily than red or blue in how humans perceive brightness. Two colors that look similarly "light" or "dark" to the eye can have meaningfully different contrast ratios against the same background, which is exactly why eyeballing contrast doesn't work and a checker is worth having.&lt;/p&gt;

&lt;p&gt;Most "suggest a fix" tools I looked at just darken or lighten until they hit the threshold, ignoring the original hue. That technically passes WCAG but can produce a color that no longer matches the brand or design intent. I ended up preserving hue and adjusting lightness within the same color family first, only shifting saturation as a fallback if that alone couldn't reach the target ratio.&lt;/p&gt;

&lt;p&gt;None of this is exotic once you know it, but I'd been treating "contrast checking" as basically solved logic before actually building one. It isn't — it's a small pile of specific rules that don't generalize the way intuition suggests.&lt;/p&gt;

&lt;p&gt;Live at quietbench.dev/contrast-checker if you want to check your own palette against it.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>The 3 mobile bugs that took longer to fix than the entire desktop version</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Sat, 04 Jul 2026 04:53:24 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/the-3-mobile-bugs-that-took-longer-to-fix-than-the-entire-desktop-version-539j</link>
      <guid>https://dev.to/aniket_saini_7/the-3-mobile-bugs-that-took-longer-to-fix-than-the-entire-desktop-version-539j</guid>
      <description>&lt;p&gt;Building the API request tester for Quietbench, the desktop version came together fast — headers, body, response view, done. Mobile is where I actually lost time.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The CORS warning banner. On desktop, a dismissible banner explaining a blocked request has plenty of room. On a narrow viewport, it either pushed the actual response out of view or got truncated into something unreadable. &lt;br&gt;
Fix was less about styling and more about rethinking the banner as collapsible-by-default on small screens, expandable on tap — not just shrinking the same layout down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The URL input row. Method dropdown + URL field + Send button in one row is fine until the viewport gets narrow enough that the URL field shrinks to a few visible characters. Testing a real API URL when you can see 8 characters of it is useless. &lt;br&gt;
Ended up stacking the method selector above the URL field on small screens instead of forcing everything into one row no matter what.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Send button itself. Small thing, but on mobile it kept ending up either off-screen when the keyboard was open, or too close to other tap targets to hit reliably.&lt;br&gt;
Pinning it above the keyboard and giving it more breathing room from neighboring elements fixed more "why isn't this working" confusion than any logic bug did.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None of these are hard problems individually. What actually cost time was assuming "responsive" meant "the same layout, smaller" — it doesn't.&lt;br&gt;
 Each of these needed an actual layout decision for narrow screens, not just a breakpoint that shrinks things proportionally.&lt;/p&gt;

&lt;p&gt;Live at quietbench.dev/api-tester if you want to try it on your phone — genuinely curious if anything's still awkward.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>tools</category>
    </item>
    <item>
      <title>Why I ripped out a cron parsing library and wrote my own</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Fri, 03 Jul 2026 04:13:27 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/why-i-ripped-out-a-cron-parsing-library-and-wrote-my-own-3d2</link>
      <guid>https://dev.to/aniket_saini_7/why-i-ripped-out-a-cron-parsing-library-and-wrote-my-own-3d2</guid>
      <description>&lt;p&gt;Building the cron builder for Quietbench, I started with an npm package for parsing and calculating next-run times. Get it working, move on. That lasted about a week.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; the library handled standard cron fine, but broke on real edge cases — conditional OR/AND behavior when day-of-week and day-of-month are combined, step values inside ranges (1-10/2), and off-by-one errors around DST transitions. When I checked its output against standard cron engines, the mismatches showed up fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not patch it:&lt;/strong&gt; the parsing and "next run time" logic were tightly coupled internally. Fixing one edge case risked breaking another. Writing something scoped to exactly what I needed was less work than fighting someone else's abstraction.&lt;/p&gt;

&lt;p&gt;The rewrite keeps three things cleanly separate: tokenize/validate each field, normalize day-of-week/day-of-month interaction explicitly, and compute next executions by walking forward in time rather than solving algebraically. Slower in theory, irrelevant in practice — nobody notices a few milliseconds when they're reading 5 output times.&lt;/p&gt;

&lt;p&gt;Building the cron builder for Quietbench, I started with an npm package for parsing and calculating next-run times. Get it working, move on. That lasted about a week.&lt;/p&gt;

&lt;p&gt;The problem: the library handled standard cron fine, but broke on real edge cases — conditional OR/AND behavior when day-of-week and day-of-month are combined, step values inside ranges (1-10/2), and off-by-one errors around DST transitions. When I checked its output against standard cron engines, the mismatches showed up fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not patch it:&lt;/strong&gt; the parsing and "next run time" logic were tightly coupled internally. Fixing one edge case risked breaking another. Writing something scoped to exactly what I needed was less work than fighting someone else's abstraction.&lt;/p&gt;

&lt;p&gt;The rewrite keeps three things cleanly separate: tokenize/validate each field, normalize day-of-week/day-of-month interaction explicitly, and compute next executions by walking forward in time rather than solving algebraically. Slower in theory, irrelevant in practice — nobody notices a few milliseconds when they're reading 5 output times.&lt;/p&gt;

&lt;p&gt;**The actual lesson: **reaching for a library first isn't wrong. But once I was spending more time reverse-engineering why the library disagreed with standard cron behavior than I would've spent writing the logic myself, that was the signal to just own it.&lt;/p&gt;

&lt;p&gt;Live at quietbench.dev/cron-builder — curious if anyone finds an edge case it still gets wrong. reaching for a library first isn't wrong. But once I was spending more time reverse-engineering why the library disagreed with standard cron behavior than I would've spent writing the logic myself, that was the signal to just own it.&lt;/p&gt;

&lt;p&gt;Live at quietbench.dev/cron-builder — curious if anyone finds an edge case it still gets wrong.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>tools</category>
    </item>
    <item>
      <title>I built a free, no-signup dev tools site because I was tired of ad-heavy formatters</title>
      <dc:creator>Aniket Saini</dc:creator>
      <pubDate>Thu, 02 Jul 2026 14:24:24 +0000</pubDate>
      <link>https://dev.to/aniket_saini_7/i-built-a-free-no-signup-dev-tools-site-because-i-was-tired-of-ad-heavy-formatters-5ha7</link>
      <guid>https://dev.to/aniket_saini_7/i-built-a-free-no-signup-dev-tools-site-because-i-was-tired-of-ad-heavy-formatters-5ha7</guid>
      <description>&lt;p&gt;Like a lot of developers, I have a handful of bookmarked utility sites I use constantly — JSON formatter, regex tester, that kind of thing. Over time most of them got slower, ad-heavier, or started asking for signups for basic features.&lt;/p&gt;

&lt;p&gt;So I built my own small suite:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JSON Formatter&lt;/strong&gt; — format/validate/minify, with a tree view for nested objects&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regex Tester&lt;/strong&gt; — live match highlighting plus a plain-English breakdown of what your pattern does&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cron Builder&lt;/strong&gt; — visual builder + parser, shows your next 5 execution times&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contrast Checker&lt;/strong&gt; — WCAG AA/AAA contrast checking with a live preview&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Tester&lt;/strong&gt; — lightweight Postman-style request tester, no install&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Everything runs client-side in the browser — no backend, no data leaves your machine, no account needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;### A few implementation notes for anyone curious&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The cron parser was the one piece I ended up writing from scratch rather than pulling in a library. I wanted predictable behavior for the "next 5 execution times" calculation without dragging in a heavy dependency.&lt;/p&gt;

&lt;p&gt;Writing a cron parser from scratch is a trap, though. I immediately hit a subtle bug in how Day-of-Month and Day-of-Week restrictions interact. In standard Unix cron, if both fields are restricted (i.e. not &lt;code&gt;*&lt;/code&gt;), the engine treats them as an &lt;code&gt;OR&lt;/code&gt; condition, not an &lt;code&gt;AND&lt;/code&gt;. My initial logic combined them with an &lt;code&gt;AND&lt;/code&gt; operator, which broke schedules like &lt;code&gt;0 0 1 * 1&lt;/code&gt; (which should run on the 1st of the month &lt;em&gt;or&lt;/em&gt; every Monday). I caught it when sanity-checking the next execution times against public standard engines, and had to rewrite the matching logic to correctly handle the conditional &lt;code&gt;OR&lt;/code&gt;/&lt;code&gt;AND&lt;/code&gt; split.&lt;/p&gt;

&lt;p&gt;Built with React + Vite + Tailwind, deployed as a static site.&lt;/p&gt;

&lt;p&gt;Would genuinely appreciate feedback — especially if anything looks broken on mobile, that's the area I'm least confident in right now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://quietbench.dev" rel="noopener noreferrer"&gt;https://quietbench.dev&lt;/a&gt;&lt;/p&gt;

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