<?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: Bright Agbomado</title>
    <description>The latest articles on DEV Community by Bright Agbomado (@relahconvert).</description>
    <link>https://dev.to/relahconvert</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3811672%2F1aab6fab-aa6b-4bc0-bf95-b36f16e96e93.png</url>
      <title>DEV Community: Bright Agbomado</title>
      <link>https://dev.to/relahconvert</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/relahconvert"/>
    <language>en</language>
    <item>
      <title>I Asked 500 Developers What AI They Use to Code. The Answers Were Surprising</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Fri, 10 Apr 2026 22:17:56 +0000</pubDate>
      <link>https://dev.to/relahconvert/i-asked-500-developers-what-ai-they-use-to-code-the-answers-were-surprising-4hi4</link>
      <guid>https://dev.to/relahconvert/i-asked-500-developers-what-ai-they-use-to-code-the-answers-were-surprising-4hi4</guid>
      <description>&lt;p&gt;I've been building &lt;a href="https://relahconvert.com" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt; — a 37-tool image toolkit — entirely with Claude Code. No traditional coding background. Just prompts and persistence.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;It got me thinking. Everyone claims to use AI for coding now. But which one actually wins in the real world?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I started paying attention. Forums, Twitter, Reddit, dev.to comments. Here's what I actually found:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The honest breakdown:&lt;/strong&gt;&lt;br&gt;
GitHub Copilot — the corporate safe choice. Used by developers who already know how to code and want autocomplete on steroids. Nobody brags about it. Nobody hates it. It just exists.&lt;/p&gt;

&lt;p&gt;ChatGPT — the first tool everyone tried. Still popular for quick questions and explaining code. But people rarely use it to actually build full projects anymore.&lt;/p&gt;

&lt;p&gt;Cursor — the new darling. Every developer on Twitter seems to be using Cursor right now. It's eating Copilot's lunch among serious developers.&lt;/p&gt;

&lt;p&gt;Claude Code — the one nobody talks about publicly but keeps appearing in solo founder stories. Especially for people building full products from scratch, not just autocompleting lines.&lt;/p&gt;

&lt;p&gt;Gemini — Google's answer. Technically impressive. Nobody seems emotionally attached to it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pattern I noticed:&lt;/strong&gt;&lt;br&gt;
Developers who already code → use Copilot or Cursor to go faster&lt;br&gt;
Non-developers building products → use Claude Code or ChatGPT to actually ship&lt;br&gt;
Two completely different use cases. Two completely different tools winning.&lt;/p&gt;

&lt;p&gt;The controversial part:&lt;br&gt;
The "vibe coder" debate is pointless.&lt;br&gt;
People who gatekeep coding — "you're not a real developer if you use AI" — are the same people who said "you're not a real developer if you use Stack Overflow" in 2010.&lt;br&gt;
The output is what matters. I shipped 37 tools in 6 weeks. I don't know what a for loop looks like from memory. My users don't care.&lt;/p&gt;

&lt;p&gt;The real question nobody asks:&lt;br&gt;
Not "which AI do you use?"&lt;br&gt;
But "did you actually ship anything?"&lt;br&gt;
Most people collecting AI coding tools haven't shipped a single thing. The tool isn't the flex. The product is.&lt;/p&gt;

&lt;p&gt;What are you actually using to build — and have you shipped something with it? 👇&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>9 Things I Did Wrong Building My Image Tool (And What Actually Fixed Them)</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Fri, 03 Apr 2026 22:12:32 +0000</pubDate>
      <link>https://dev.to/relahconvert/9-things-i-did-wrong-building-my-image-tool-and-what-actually-fixed-them-326l</link>
      <guid>https://dev.to/relahconvert/9-things-i-did-wrong-building-my-image-tool-and-what-actually-fixed-them-326l</guid>
      <description>&lt;p&gt;I've been building &lt;a href="https://relahconvert.com/passport-photo" rel="noopener noreferrer"&gt;Relahconvert&lt;/a&gt; — a free browser-based image toolkit — for about a month now. 37 tools, 25 languages, zero backend for most of it.&lt;br&gt;
Sounds clean. It wasn't 😄&lt;br&gt;
Here are 9 real mistakes I made and what actually solved them.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;"I'll just use a library for that" → Canvas API&lt;br&gt;
My first instinct for image processing was to reach for a library. Turns out the browser's Canvas API handles resize, crop, flip, grayscale, and more natively. No dependencies. No bundle size. Just pixels.&lt;br&gt;
&lt;code&gt;js&lt;br&gt;
const ctx = canvas.getContext('2d');&lt;br&gt;
ctx.drawImage(img, 0, 0, newWidth, newHeight);&lt;br&gt;
canvas.toBlob(blob =&amp;gt; downloadFile(blob), 'image/jpeg', 0.9);&lt;/code&gt;&lt;br&gt;
I now use this for 90% of my tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Dark mode needs JavaScript" → prefers-color-scheme&lt;br&gt;
I built a whole JS toggle system before realizing the browser already knows what the user wants.&lt;br&gt;
css@media (prefers-color-scheme: dark) {&lt;br&gt;
:root {&lt;br&gt;
--bg: #1a1a1a;&lt;br&gt;
--text: #f0f0f0;&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
Still kept the manual toggle — but the default is now instant and correct.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"I need a backend for file downloads" → URL.createObjectURL&lt;br&gt;
I thought serving processed images required a server. Nope.&lt;br&gt;
jsconst url = URL.createObjectURL(blob);&lt;br&gt;
const a = document.createElement('a');&lt;br&gt;
a.href = url;&lt;br&gt;
a.download = 'converted.png';&lt;br&gt;
a.click();&lt;br&gt;
URL.revokeObjectURL(url);&lt;br&gt;
Everything stays in the browser. No uploads. No server costs. Users love the privacy angle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Batch processing will kill performance" → Web Workers&lt;br&gt;
Processing 25 images at once was freezing the UI. Web Workers run in a separate thread — the page stays responsive while the heavy lifting happens in the background.&lt;br&gt;
jsconst worker = new Worker('process.js');&lt;br&gt;
worker.postMessage({ imageData, format: 'webp' });&lt;br&gt;
worker.onmessage = e =&amp;gt; renderResult(e.data);&lt;br&gt;
Game changer for batch tools.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"I need an API for compression" → canvas.toBlob quality param&lt;br&gt;
I almost paid for a compression API. Then I noticed toBlob has a quality parameter.&lt;br&gt;
jscanvas.toBlob(blob =&amp;gt; save(blob), 'image/jpeg', 0.7);&lt;br&gt;
0.7 gives you roughly 60-70% size reduction with barely visible quality loss. Free. Built-in. Already there.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"RTL Arabic will break my layout" → CSS logical properties&lt;br&gt;
Supporting 25 languages including Arabic felt terrifying. Logical properties made it manageable.&lt;br&gt;
css.tool-container {&lt;br&gt;
margin-inline-start: 1rem;&lt;br&gt;
padding-inline: 1.5rem;&lt;br&gt;
}&lt;br&gt;
One declaration. Works LTR and RTL automatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"I'll handle the API key in the frontend" → Cloudflare Workers&lt;br&gt;
I exposed an API key in my frontend. Bots found it within days 😬&lt;br&gt;
The fix: a Cloudflare Worker as a proxy. Your key lives server-side, requests go through the worker, users never see it.&lt;br&gt;
jsexport default {&lt;br&gt;
async fetch(request) {&lt;br&gt;
const response = await fetch('&lt;a href="https://api.remove.bg/v1.0/removebg" rel="noopener noreferrer"&gt;https://api.remove.bg/v1.0/removebg&lt;/a&gt;', {&lt;br&gt;
  method: 'POST',&lt;br&gt;
  headers: { 'X-Api-Key': API_KEY },&lt;br&gt;
  body: await request.formData()&lt;br&gt;
});&lt;br&gt;
return response;&lt;br&gt;
}&lt;br&gt;
}&lt;br&gt;
Lesson learned the hard way.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"Multi-language SEO is just hreflang tags" → it's not&lt;br&gt;
I had hreflang conflicts with canonical tags for weeks and couldn't figure out why my impressions were dropping. Canonicals, sitemaps, and hreflang all need to agree with each other.&lt;br&gt;
html&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
One wrong canonical and Google ignores your entire language setup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;"More tools = more traffic" → wrong&lt;br&gt;
I built 37 tools thinking volume would win. But 37 unindexed tools is worth less than 5 indexed and ranking ones.&lt;br&gt;
Now I ask before building: is this keyword searchable? Is the difficulty realistic for my domain authority? Does it solve a real problem?&lt;br&gt;
Tools are only as valuable as the traffic they attract.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What I'm still figuring out&lt;/p&gt;

&lt;p&gt;Supabase auth across 25 languages&lt;br&gt;
Getting Google to index all 950 pages faster&lt;br&gt;
Whether PDF to PNG is worth the complexity&lt;/p&gt;

&lt;p&gt;Building in public is humbling. But the browser is genuinely more powerful than most tutorials let on — and that's what makes solo projects like this possible.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>beginners</category>
      <category>javascript</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I launched a free image tool 30 days ago. Here's what Google did next</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Tue, 31 Mar 2026 23:12:49 +0000</pubDate>
      <link>https://dev.to/relahconvert/i-launched-a-free-image-tool-30-days-ago-heres-what-google-did-next-2cab</link>
      <guid>https://dev.to/relahconvert/i-launched-a-free-image-tool-30-days-ago-heres-what-google-did-next-2cab</guid>
      <description>&lt;p&gt;30 days ago I launched &lt;a href="https://relahconvert.com/compress" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt; — a free browser-based image toolkit with 37 tools across 25 languages.&lt;/p&gt;

&lt;p&gt;I thought the hard part was building it. I was wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Week Felt Amazing
&lt;/h2&gt;

&lt;p&gt;Impressions climbed daily. Pages were getting indexed fast. &lt;br&gt;
GSC was showing 100-150 impressions per day. I thought I was &lt;br&gt;
onto something.&lt;/p&gt;

&lt;p&gt;Then Google pulled the rug.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Drop Nobody Warns You About
&lt;/h2&gt;

&lt;p&gt;Around day 20, impressions crashed to near zero. Some days &lt;br&gt;
literally 0 or 1 impression.&lt;/p&gt;

&lt;p&gt;Meanwhile GSC kept indexing more pages. 207 indexed. Then &lt;br&gt;
952 Pages being discovered.&lt;/p&gt;

&lt;p&gt;But impressions? Flatline.&lt;/p&gt;

&lt;p&gt;I spent days trying to figure out what I did wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Actually Found
&lt;/h2&gt;

&lt;p&gt;Running a Semrush audit revealed three real issues:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;48 hreflang conflicts&lt;/strong&gt; — my language pages had canonical &lt;br&gt;
tags pointing to the English version instead of themselves. &lt;br&gt;
Google was getting contradictory signals on 48 pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;24 incorrect sitemap URLs&lt;/strong&gt; — a trailing slash &lt;br&gt;
inconsistency between my sitemap and canonical tags. &lt;br&gt;
The sitemap said /compress/ but the canonical said /compress.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; Google was seeing 3 different signals for the &lt;br&gt;
same URL and didn't know which one to trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Each language page canonical now points to itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/fr/compress/ canonical → relahconvert.com/fr/compress/&lt;/li&gt;
&lt;li&gt;/ar/compress/ canonical → relahconvert.com/ar/compress/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the sitemap now consistently matches the canonical &lt;br&gt;
format across all 1,075 URLs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happened After
&lt;/h2&gt;

&lt;p&gt;External backlinks jumped from 2 to 10 in GSC.&lt;br&gt;
Internal links jumped from 531 to 1,770.&lt;br&gt;
FAQ rich results grew from 38 to 57.&lt;/p&gt;

&lt;p&gt;Impressions? Still recovering. I learnt Google needs 2-4 weeks &lt;br&gt;
to recrawl and reassess after canonical changes.&lt;/p&gt;

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

&lt;p&gt;Google doesn't punish you for fixing things. But it &lt;br&gt;
does take time to process changes — especially on a &lt;br&gt;
domain that's only 30 days old.&lt;/p&gt;

&lt;p&gt;The hardest part isn't the technical fixes. It's &lt;br&gt;
watching your numbers flatline while knowing the &lt;br&gt;
fix is in and you just have to wait.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where I Am Now
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;207 pages indexed&lt;/li&gt;
&lt;li&gt;57 valid FAQ rich results&lt;/li&gt;
&lt;li&gt;10 external backlinks&lt;/li&gt;
&lt;li&gt;1,770 internal links&lt;/li&gt;
&lt;li&gt;Position 76 average (working on it)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Day 30. Still building. Still waiting.&lt;/p&gt;

&lt;p&gt;If you're in the same spot — new site, confusing GSC &lt;br&gt;
data, impression drops that make no sense — you're &lt;br&gt;
probably not doing anything wrong. Google just takes &lt;br&gt;
time with new domains.&lt;/p&gt;

&lt;p&gt;Building &lt;a href="https://relahconvert.com/compress" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt; in public&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>seo</category>
      <category>beginners</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How I Got 149 Pages Indexed in 27 Days With a New Domain</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Sat, 28 Mar 2026 23:23:10 +0000</pubDate>
      <link>https://dev.to/relahconvert/how-i-got-149-pages-indexed-in-27-days-with-a-new-domain-17pp</link>
      <guid>https://dev.to/relahconvert/how-i-got-149-pages-indexed-in-27-days-with-a-new-domain-17pp</guid>
      <description>&lt;p&gt;When I launched &lt;a href="https://relahconvert.com" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt; — a free browser-based image toolkit — I had one big SEO concern: would Google even bother indexing a brand new domain with hundreds of pages?&lt;/p&gt;

&lt;p&gt;27 days later, 149 pages are indexed with 816 still pending. &lt;br&gt;
Here's exactly what I did and what I learned.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Site Structure
&lt;/h2&gt;

&lt;p&gt;RelahConvert has 37 image tools across 25 languages. That's &lt;br&gt;
theoretically 925 pages total. Getting Google to find and &lt;br&gt;
index all of them quickly required being intentional about &lt;br&gt;
a few things.&lt;/p&gt;
&lt;h2&gt;
  
  
  1. Submit a Sitemap Immediately
&lt;/h2&gt;

&lt;p&gt;The first thing I did after launching was submit a sitemap &lt;br&gt;
to Google Search Console. This tells Google exactly which &lt;br&gt;
pages exist and where to find them.&lt;/p&gt;

&lt;p&gt;In Vite, generating a sitemap is straightforward with &lt;br&gt;
vite-plugin-sitemap:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;sitemap&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite-plugin-sitemap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://relahconvert.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submit it in GSC under Sitemaps and Google will start &lt;br&gt;
crawling within days.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Strong Internal Linking
&lt;/h2&gt;

&lt;p&gt;Every tool page on RelahConvert links to related tools &lt;br&gt;
through the navbar, footer, and a "What's Next" section &lt;br&gt;
after each conversion. This means Googlebot can crawl &lt;br&gt;
from any page to every other page easily.&lt;/p&gt;

&lt;p&gt;GSC confirmed 531 internal links across the site. That's &lt;br&gt;
Googlebot's roadmap.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Request Indexing for Priority Pages
&lt;/h2&gt;

&lt;p&gt;For your most important pages don't just wait — request &lt;br&gt;
indexing manually in GSC using the URL Inspection tool.&lt;/p&gt;

&lt;p&gt;Enter the URL → click "Request Indexing" → Google &lt;br&gt;
prioritizes crawling that page.&lt;/p&gt;

&lt;p&gt;I did this for my core tool pages and they showed up in &lt;br&gt;
results within days.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. FAQ Structured Data
&lt;/h2&gt;

&lt;p&gt;Every tool page has FAQ schema markup. Within 27 days &lt;br&gt;
GSC showed 48 valid FAQ rich results with zero errors.&lt;/p&gt;

&lt;p&gt;This doesn't directly cause indexing but it signals to &lt;br&gt;
Google that your pages are well structured and trustworthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Be Patient With Multilingual Pages
&lt;/h2&gt;

&lt;p&gt;With 25 languages, most of my non-English pages are still &lt;br&gt;
in the "Discovered — not yet indexed" queue (964 pages). &lt;br&gt;
Google indexes the primary language first then works &lt;br&gt;
through translations.&lt;/p&gt;

&lt;p&gt;Make sure your hreflang tags are correct so Google &lt;br&gt;
understands the relationship between language versions.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Actually Indexed After 27 Days
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;149 pages indexed&lt;/li&gt;
&lt;li&gt;964 discovered but pending&lt;/li&gt;
&lt;li&gt;1,140 impressions in 28 days&lt;/li&gt;
&lt;li&gt;Position 76 average (still early)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The indexing is happening. The rankings take longer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Reality
&lt;/h2&gt;

&lt;p&gt;Getting pages indexed quickly is the easy part. Getting &lt;br&gt;
them to rank is the slow part that requires backlinks, &lt;br&gt;
time, and domain authority that a 27 day old site simply &lt;br&gt;
doesn't have yet.&lt;/p&gt;

&lt;p&gt;But you can't rank what isn't indexed. Step one is done.&lt;/p&gt;

&lt;p&gt;37 free image tools at &lt;a href="https://relahconvert.com" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>seo</category>
    </item>
    <item>
      <title>How I Added Dark Mode to a 37-Tool Vite SPA in One Prompt</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Tue, 24 Mar 2026 23:41:18 +0000</pubDate>
      <link>https://dev.to/relahconvert/how-i-added-dark-mode-to-a-37-tool-vite-spa-in-one-prompt-3o88</link>
      <guid>https://dev.to/relahconvert/how-i-added-dark-mode-to-a-37-tool-vite-spa-in-one-prompt-3o88</guid>
      <description>&lt;p&gt;I've been building RelahConvert — a browser-only image converter &lt;br&gt;
with 37 tools — and yesterday I decided to add dark mode.&lt;/p&gt;

&lt;p&gt;I was expecting it to take hours. It took minutes.&lt;/p&gt;

&lt;p&gt;Here's exactly how it works and what I learned.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem With Hardcoded Colors
&lt;/h2&gt;

&lt;p&gt;Most projects start with colors scattered everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;#ffffff&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;color&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#1&lt;/span&gt;&lt;span class="nt"&gt;a1a1a&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;border&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="err"&gt;1&lt;/span&gt;&lt;span class="nt"&gt;px&lt;/span&gt; &lt;span class="nt"&gt;solid&lt;/span&gt; &lt;span class="nf"&gt;#e0e0e0&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you have 37 tool pages, finding and replacing every &lt;br&gt;
hardcoded color manually would take forever. There had to be &lt;br&gt;
a better way.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Solution: CSS Variables + data-theme
&lt;/h2&gt;

&lt;p&gt;The entire dark mode system comes down to two things:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Define all colors as CSS variables&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#ffffff&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#1a1a1a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f5f5f5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#e0e0e0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;data-theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"dark"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--bg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#18181b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f4f4f5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#27272a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;--border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#3f3f46&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2. Toggle the attribute on the root element&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toggle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the whole system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remembering the Preference
&lt;/h2&gt;

&lt;p&gt;You also want to respect the user's OS preference on first &lt;br&gt;
visit, then let them override manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// On page load&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;prefersDark&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;matchMedia&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;(prefers-color-scheme: dark)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;prefersDark&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data-theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Toggle Button
&lt;/h2&gt;

&lt;p&gt;A simple sun/moon icon in the navbar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;icon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;☀️&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;🌙&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Place it top right — that's where users expect it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for Dark Mode That Doesn't Look Weird
&lt;/h2&gt;

&lt;p&gt;A few things I learned:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Never use pure black (#000000)&lt;/strong&gt; — use #18181b or similar. 
Pure black feels harsh.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never use pure white text&lt;/strong&gt; — use #f4f4f5. Pure white on 
dark backgrounds causes eye strain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Give cards depth&lt;/strong&gt; — make cards slightly lighter than the 
background so elements don't flatten out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Watch out for images&lt;/strong&gt; — if users upload images with white 
backgrounds, they'll float awkwardly on dark pages. Keep 
preview areas neutral.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Result&lt;/p&gt;

&lt;p&gt;38 tool pages, all consistently dark, zero hardcoded color &lt;br&gt;
conflicts. The site went from feeling like a utility tool to &lt;br&gt;
feeling like a proper app.&lt;/p&gt;

&lt;p&gt;If you're building a Vite SPA and haven't added dark mode yet &lt;br&gt;
— it's simpler than you think. One CSS variable system and a &lt;br&gt;
10-line toggle is all it takes.&lt;/p&gt;

&lt;p&gt;Built with Vite. All processing is browser-only — files never &lt;br&gt;
leave the device.&lt;/p&gt;

&lt;p&gt;Check it out at &lt;a href="https://relahconvert.com/" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>css</category>
      <category>vite</category>
    </item>
    <item>
      <title>I launched a free image tool site 3 weeks ago. Here's what actually happened.</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Mon, 23 Mar 2026 11:55:59 +0000</pubDate>
      <link>https://dev.to/relahconvert/i-launched-a-free-image-tool-site-3-weeks-ago-heres-what-actually-happened-3onk</link>
      <guid>https://dev.to/relahconvert/i-launched-a-free-image-tool-site-3-weeks-ago-heres-what-actually-happened-3onk</guid>
      <description>&lt;p&gt;3 weeks ago I launched relahconvert.com — a free browser-based image converter with 37 tools and 25 languages.&lt;br&gt;
Here's the honest numbers so far:&lt;/p&gt;

&lt;p&gt;1,090 Google impressions&lt;br&gt;
11 real clicks&lt;br&gt;
Position 76 average&lt;br&gt;
2 external backlinks (both from dev.to)&lt;br&gt;
109 pages indexed out of 843&lt;/p&gt;

&lt;p&gt;Not viral. Not impressive. But moving in the right direction.&lt;br&gt;
What I thought would happen:&lt;br&gt;
Launch, get traffic, make money.&lt;br&gt;
What actually happened:&lt;br&gt;
Built 37 tools. Realized no one can find you without backlinks. Realized backlinks require effort. Realized SEO takes months not days.&lt;br&gt;
What I learned:&lt;br&gt;
Building is the easy part. Distribution is the real work.&lt;br&gt;
Everyone talks about what they built. Nobody talks about the 3 weeks after launch when Google doesn't care you exist yet.&lt;br&gt;
I'm documenting the whole journey — the tools, the SEO, the slow grind of getting traffic from zero.&lt;br&gt;
If you're building something right now and wondering why nothing is happening yet — you're not alone.&lt;br&gt;
Try the tools here: &lt;a href="https://relahconvert.com" rel="noopener noreferrer"&gt;https://relahconvert.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>showdev</category>
      <category>javascript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I built a free passport photo maker for 160+ countries — no server uploads</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Sat, 21 Mar 2026 18:59:06 +0000</pubDate>
      <link>https://dev.to/relahconvert/i-built-a-free-passport-photo-maker-for-160-countries-no-server-uploads-1bbf</link>
      <guid>https://dev.to/relahconvert/i-built-a-free-passport-photo-maker-for-160-countries-no-server-uploads-1bbf</guid>
      <description>&lt;p&gt;I just added a passport photo maker to RelahConvert — here's what makes it different.&lt;br&gt;
Most passport photo tools upload your photo to their server, process it, then send it back. That means your face is sitting on some random server somewhere.&lt;br&gt;
Mine works entirely in the browser. The photo never leaves your device.&lt;br&gt;
What it does:&lt;/p&gt;

&lt;p&gt;Supports 160+ countries with correct dimensions&lt;br&gt;
Auto-detects and crops to head and shoulders&lt;br&gt;
Removes background using AI (runs locally in browser)&lt;br&gt;
Downloads single photo or printable 4×6 sheet&lt;br&gt;
Available in 25 languages.&lt;/p&gt;

&lt;p&gt;The hard part was getting the crop right for every photo type — full body, portrait, headshot. Still not perfect but works well for standard portrait photos.&lt;br&gt;
Built with vanilla JS + Canvas API + &lt;a class="mentioned-user" href="https://dev.to/imgly"&gt;@imgly&lt;/a&gt;/background-removal for the AI part.&lt;br&gt;
Try it here: Try it here: &lt;a href="https://relahconvert.com/passport-photo" rel="noopener noreferrer"&gt;https://relahconvert.com/passport-photo&lt;/a&gt;&lt;br&gt;
Would love feedback — especially if the crop doesn't work for your photo type.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>showdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>I built a free browser-based image converter — no uploads, files never leave your device</title>
      <dc:creator>Bright Agbomado</dc:creator>
      <pubDate>Sat, 07 Mar 2026 14:15:44 +0000</pubDate>
      <link>https://dev.to/relahconvert/i-built-a-free-browser-based-image-converter-no-uploads-files-never-leave-your-device-21nf</link>
      <guid>https://dev.to/relahconvert/i-built-a-free-browser-based-image-converter-no-uploads-files-never-leave-your-device-21nf</guid>
      <description>&lt;p&gt;I've been frustrated with image tools that upload your files to their &lt;br&gt;
servers. You never really know what happens to your photos after that.&lt;/p&gt;

&lt;p&gt;So I built RelahConvert — a completely free image tool suite that runs &lt;br&gt;
100% in your browser. No uploads, no servers, no accounts required.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Compress images — reduce file size while keeping quality&lt;/li&gt;
&lt;li&gt;Resize images — by pixels or percentage&lt;/li&gt;
&lt;li&gt;Convert between JPG, PNG and WebP formats&lt;/li&gt;
&lt;li&gt;Convert images to PDF&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All 10 tools are free and your files never leave your device. Everything &lt;br&gt;
runs using the browser's built-in Canvas API.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works technically
&lt;/h2&gt;

&lt;p&gt;Instead of sending files to a server, I use the HTML5 Canvas element to &lt;br&gt;
process images directly in the browser. The user picks a file, Canvas &lt;br&gt;
reads the pixel data, applies the transformation, and outputs the result &lt;br&gt;
— all locally.&lt;/p&gt;

&lt;p&gt;For the PDF conversion I used a lightweight JS library to bundle images &lt;br&gt;
into a proper PDF structure without any server involvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;I'm adding 30 more tools over the next few weeks including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GIF, BMP and TIFF conversions&lt;/li&gt;
&lt;li&gt;Crop, rotate and flip&lt;/li&gt;
&lt;li&gt;Grayscale, brightness and contrast adjustments&lt;/li&gt;
&lt;li&gt;Watermark tool&lt;/li&gt;
&lt;li&gt;EXIF metadata remover&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;a href="https://relahconvert.com" rel="noopener noreferrer"&gt;RelahConvert&lt;/a&gt; — completely free, no account needed.&lt;/p&gt;

&lt;p&gt;Would love any feedback from the dev community on the approach or &lt;br&gt;
any tools you'd like to see added.&lt;/p&gt;

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