<?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: chuanbuilds</title>
    <description>The latest articles on DEV Community by chuanbuilds (@chuanbuilds).</description>
    <link>https://dev.to/chuanbuilds</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%2F3934283%2Ff09f8acd-a946-4882-b570-c88744993267.png</url>
      <title>DEV Community: chuanbuilds</title>
      <link>https://dev.to/chuanbuilds</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chuanbuilds"/>
    <language>en</language>
    <item>
      <title>My Inverter Kept Tripping Until I Learned Running Watts Surge Watts</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Thu, 13 Aug 2026 08:34:39 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/my-inverter-kept-tripping-until-i-learned-running-watts-surge-watts-4nkc</link>
      <guid>https://dev.to/chuanbuilds/my-inverter-kept-tripping-until-i-learned-running-watts-surge-watts-4nkc</guid>
      <description>&lt;p&gt;When I wired the electrical system in my campervan, I picked a 1000W pure-sine inverter. My loads summed to about 700W, so 1000W felt like comfortable headroom. Then I plugged in a 800W coffee maker and the inverter shut off instantly. Every time.&lt;/p&gt;

&lt;p&gt;Turns out I'd sized for the wrong number.&lt;/p&gt;

&lt;p&gt;There are two wattage figures for almost every device with a motor or compressor: running watts (what it draws steadily) and surge watts (what it yanks for a fraction of a second at startup). A coffee maker, a fridge compressor, a power tool, a vacuum — they all spike on startup, often 2–4× the running draw. My 800W coffee maker was surging close to 1600W the moment it switched on, and my 1000W inverter, rated for maybe 2000W surge for a few milliseconds, was not having it under a cold start.&lt;/p&gt;

&lt;p&gt;The fix isn't just "buy a bigger inverter," either. Oversizing has its own cost: inverters are most efficient at mid-load, and a 3000W unit running a 50W fan wastes an ugly chunk of power just staying awake. You want headroom over the combined surge of everything that could run at once — not the running sum, and not a blind max.&lt;/p&gt;

&lt;p&gt;So I listed every device I'd ever run off inverter power, with both numbers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Device&lt;/th&gt;
&lt;th&gt;Running&lt;/th&gt;
&lt;th&gt;Surge&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fridge compressor&lt;/td&gt;
&lt;td&gt;45W&lt;/td&gt;
&lt;td&gt;120W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Coffee maker&lt;/td&gt;
&lt;td&gt;800W&lt;/td&gt;
&lt;td&gt;1600W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Laptop charger&lt;/td&gt;
&lt;td&gt;90W&lt;/td&gt;
&lt;td&gt;90W&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Phone&lt;/td&gt;
&lt;td&gt;18W&lt;/td&gt;
&lt;td&gt;18W&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Coffee + fridge starting together = ~1720W surge. That's the number the inverter has to survive for a second, not the 953W running total. I landed on a 2000W pure-sine unit and the trips stopped.&lt;/p&gt;

&lt;p&gt;One more thing people skip: pure-sine vs modified-sine matters for anything with electronics in it. Cheap modified-sine inverters can fry sensitive gear or make weird noises in speakers. For a van where you're charging laptops and running a fridge controller, pure-sine is not optional.&lt;/p&gt;

&lt;p&gt;I worked the whole thing through &lt;a href="https://camppowercalc.com/en/" rel="noopener noreferrer"&gt;CampPowerCalc&lt;/a&gt; and their &lt;a href="https://camppowercalc.com/en/blog/campervan-inverter-sizing-guide/" rel="noopener noreferrer"&gt;campervan inverter sizing guide&lt;/a&gt; — it walks through exactly this running-vs-surge step instead of just telling you to add up watts. The &lt;a href="https://en.wikipedia.org/wiki/Power_inverter" rel="noopener noreferrer"&gt;power inverter&lt;/a&gt; page on Wikipedia is a decent reference if you want the electrical background.&lt;/p&gt;

&lt;p&gt;If your inverter trips on one specific thing, don't assume the device is broken. Check its surge draw first.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I Built a Tariff Lookup and Learned Why "Laptop" Is Not a Good Enough Word</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Tue, 11 Aug 2026 09:07:50 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-built-a-tariff-lookup-and-learned-why-laptop-is-not-a-good-enough-word-59j4</link>
      <guid>https://dev.to/chuanbuilds/i-built-a-tariff-lookup-and-learned-why-laptop-is-not-a-good-enough-word-59j4</guid>
      <description>&lt;p&gt;Shipping side project hardware internationally made me sit down and actually read the Harmonized System for the first time. Ports and laptops, it turns out, do not live in the same subheading. A laptop is 8471.30 (portable automatic data processing machines); a port replicator or USB hub is a different heading entirely. Same desk, different tax rate.&lt;/p&gt;

&lt;p&gt;The interesting engineering problem: tariff schedules are hierarchical — 2-digit chapter, 4-digit heading, 6-digit subheading — and the first six digits are shared across 200+ countries. That means one lookup table can serve the US, EU, UK and China, which is exactly the kind of data structure you want as a static export.&lt;/p&gt;

&lt;p&gt;I documented the classification logic while building a &lt;a href="https://tariffpedia.com/hs-code/847130/" rel="noopener noreferrer"&gt;laptop import duty reference&lt;/a&gt; and it's been the single most useful artifact for quoting customers accurate landed costs. The code is boring; the data model is the product.&lt;/p&gt;

</description>
      <category>buildinpublic</category>
      <category>hardware</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>I sized my camping battery wrong three times before I built a calculator for it</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Tue, 11 Aug 2026 08:06:35 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-sized-my-camping-battery-wrong-three-times-before-i-built-a-calculator-for-it-1km3</link>
      <guid>https://dev.to/chuanbuilds/i-sized-my-camping-battery-wrong-three-times-before-i-built-a-calculator-for-it-1km3</guid>
      <description>&lt;p&gt;The first time I killed a battery at 2am, it was my own fault. I'd added up the watts on the stickers — fridge 45W, lights 10W, phone 12W — and rounded up to a 100Ah battery. What I'd missed is that "watts on a label" and "amp-hours in a box" aren't the same unit, and a compressor fridge spikes to 3–4× its running draw the second it kicks on.&lt;/p&gt;

&lt;p&gt;The second time, I'd learned about watt-hours but forgot the inverter efficiency loss. The third time, I trusted the "up to 8 hours" claim on a product page that was measured at the fridge's &lt;em&gt;minimum&lt;/em&gt; setting with nothing else running.&lt;/p&gt;

&lt;p&gt;So I sat down and actually worked the math. The unit that matters is watt-hours — watts × hours. A 45W fridge running 24h isn't 45Wh, it's ~1,080Wh, and that's before the surge tax. Here's the tiny function I kept reaching for:&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;// watts pulled, hours run per day, plus a safety buffer&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;dailyWh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&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;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;devices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watts&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hours&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="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;buffer&lt;/span&gt;&lt;span class="p"&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;rig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;45&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;  &lt;span class="c1"&gt;// compressor fridge, runs near-constant&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;   &lt;span class="c1"&gt;// LED lights&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;watts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="c1"&gt;// phone + laptop top-up&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;dailyWh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rig&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c1"&gt;// ~1354 Wh needed per day&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That 1,354Wh is the number you actually size against — not the 67W sum of the stickers. Then you divide by your battery's nominal voltage to get amp-hours, and shave off ~20% so you're not parking a lithium cell at 100% discharge every night (which quietly halves its lifespan).&lt;/p&gt;

&lt;p&gt;Once I'd done this by hand one too many times, I put it into a &lt;a href="https://camppowercalc.com/en/" rel="noopener noreferrer"&gt;&lt;strong&gt;camping power calculator&lt;/strong&gt;&lt;/a&gt; so I'd stop redoing the arithmetic on the back of a receipt. It walks the same path — list the devices, get the real Wh, then the battery and solar size that actually hold — and it's the thing I now send to friends instead of a paragraph of text.&lt;/p&gt;

&lt;p&gt;Solar is the part people get backwards. A panel's "100W" is a lab number at perfect noon sun; you realistically collect 4–6 sun-hours a day, and only in summer. So a 100W panel is closer to 400–600Wh/day, not 2,400. If your rig eats 1,354Wh, one panel won't keep up — you need two, or a smaller fridge. The physics here is worth reading up on; &lt;a href="https://en.wikipedia.org/wiki/Watt-hour" rel="noopener noreferrer"&gt;watt-hour&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Photovoltaic_system" rel="noopener noreferrer"&gt;photovoltaic system&lt;/a&gt; are the two pages I wish I'd opened before trip one.&lt;/p&gt;

&lt;p&gt;The takeaway I keep repeating to myself: size for the &lt;em&gt;peak and the real daily draw&lt;/em&gt;, not the sticker sum. A 20% buffer isn't optional padding, it's the difference between a battery that lasts the season and one you're replacing in the spring.&lt;/p&gt;

</description>
      <category>camping</category>
      <category>offgrid</category>
      <category>javascript</category>
      <category>showdev</category>
    </item>
    <item>
      <title>I finally stopped hand-indenting YAML. Here's the local converter I added to my toolkit</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Fri, 07 Aug 2026 07:51:06 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-finally-stopped-hand-indenting-yaml-heres-the-local-converter-i-added-to-my-toolkit-52o4</link>
      <guid>https://dev.to/chuanbuilds/i-finally-stopped-hand-indenting-yaml-heres-the-local-converter-i-added-to-my-toolkit-52o4</guid>
      <description>&lt;p&gt;YAML is fine until it isn't. I keep a bunch of config files for side projects — CI pipelines, Docker compose, some Kubernetes manifests — and every time I need to move a JSON blob into one of them, I end up hand-converting it. That's how you get an hour of debugging a single missing space.&lt;/p&gt;

&lt;p&gt;The annoying part is the tools. The converters you find by searching either upload your file somewhere or make you paste config into a third-party server. For a config file that contains API keys or internal URLs, that's a non-starter for me.&lt;/p&gt;

&lt;p&gt;So I added a JSON ↔ YAML converter that runs entirely in the browser to my collection of client-side tools:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://untrackedtools.com/en/tools/json-yaml-converter/" rel="noopener noreferrer"&gt;&lt;strong&gt;JSON to YAML converter&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It does the two directions. Paste JSON, get YAML — or paste YAML, get JSON. Output is a one-click copy, nothing leaves the tab, no upload, no account. The conversion itself is standard library logic, not some ML thing, so what you get out is deterministic and lossless for valid input.&lt;/p&gt;

&lt;p&gt;A quick example, because it's the kind of thing that looks trivial until you've been burned by it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"api"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"registry.example.com/api:2.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"ports"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"8080:80"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"environment"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"DB_HOST"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"postgres"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"DB_PORT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"5432"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hand-writing that as YAML means getting every level of indentation right:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;api&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry.example.com/api:2.4&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;8080:80&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;DB_HOST&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres&lt;/span&gt;
      &lt;span class="na"&gt;DB_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;5432'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One wrong space and your container just... doesn't come up. The converter removes the whole class of mistake — you work in the format you're comfortable in, and paste the result into the config.&lt;/p&gt;

&lt;p&gt;It joins 100-plus tools in the &lt;a href="https://untrackedtools.com/en/" rel="noopener noreferrer"&gt;Untracked Tools&lt;/a&gt; collection, all client-side for the same privacy reason. If you deal with config files at all, bookmark the converter — it's one of those "saved me on a Friday afternoon" tools.&lt;/p&gt;

</description>
      <category>json</category>
      <category>yaml</category>
      <category>tools</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Built a Free Invoice Generator for Freelancers — Here's What Shipping Solo Taught Me</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Thu, 30 Jul 2026 07:46:45 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-built-a-free-invoice-generator-for-freelancers-heres-what-shipping-solo-taught-me-34g6</link>
      <guid>https://dev.to/chuanbuilds/i-built-a-free-invoice-generator-for-freelancers-heres-what-shipping-solo-taught-me-34g6</guid>
      <description>&lt;p&gt;Like a lot of freelancers, I got frustrated with the same two bad options for sending invoices: hand-formatting them in Word, or signing up for a full accounting suite just to export a PDF.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;InvoiceFormly&lt;/strong&gt; (&lt;a href="https://invoiceformly.com/en/" rel="noopener noreferrer"&gt;https://invoiceformly.com/en/&lt;/a&gt;) — a free, browser-based invoice generator. Type your line items, drop in your logo, and download a clean PDF. No sign-up required for basic use.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15&lt;/strong&gt; (App Router) deployed on &lt;strong&gt;Cloudflare Pages&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PayPal Subscriptions&lt;/strong&gt; for the optional Pro tier&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The interesting bits
&lt;/h2&gt;

&lt;p&gt;The trickiest parts were PDF rendering fidelity across browsers and handling tax/rounding correctly for multiple currencies. I kept the editor and the exported PDF layout in sync so what you see is exactly what gets sent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I'm posting
&lt;/h2&gt;

&lt;p&gt;I'm a solo indie developer and this is my first real SaaS. If you send invoices as a freelancer or run a small business, give it a try: &lt;a href="https://invoiceformly.com/en/" rel="noopener noreferrer"&gt;https://invoiceformly.com/en/&lt;/a&gt;. I'd genuinely love feedback — especially from anyone who's solved cross-currency tax edge cases cleanly.&lt;/p&gt;

&lt;p&gt;Happy to answer anything about the build in the comments.&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>nextjs</category>
      <category>saas</category>
    </item>
    <item>
      <title>I killed my campervan battery on night one. So I built a power calculator.</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Fri, 17 Jul 2026 00:28:29 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-killed-my-campervan-battery-on-night-one-so-i-built-a-power-calculator-b38</link>
      <guid>https://dev.to/chuanbuilds/i-killed-my-campervan-battery-on-night-one-so-i-built-a-power-calculator-b38</guid>
      <description>&lt;p&gt;The first night in the van, I ran the fridge, charged a laptop, and left a light on. By 11pm the battery was dead and my phone was at 2%. I'd "estimated" my power needs the way you estimate how much pizza to order — vaguely, and wrong.&lt;/p&gt;

&lt;p&gt;Turns out off-grid power isn't that complicated, it's just unforgiving if you guess. You need to know how many watts each thing pulls, for how many hours a day, and then size a battery and solar to cover it with some margin. The math is simple; doing it in your head at a campsite is not.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://camppowercalc.com/en/" rel="noopener noreferrer"&gt;CampPowerCalc&lt;/a&gt;. You tell it the appliances you actually run — fan, fridge, laptop, lights, water pump — and roughly how long each runs, and it works out the watt-hours, then sizes the battery and solar you'd want for vanlife, RV, or just a weekend off-grid. It uses real appliance draw data and straight physics, no "trust me bro" fudge factors.&lt;/p&gt;

&lt;p&gt;The thing I like is it shows the gap. My first plan was way under-sized; seeing the number made me buy one bigger battery instead of discovering the shortfall at 2am in the woods. Different setups need different answers, so treat the result as a solid starting point and sanity-check it against your own gear — but it beats guessing and eating cold food.&lt;/p&gt;

&lt;p&gt;If you're planning any off-grid power, it's here: &lt;a href="https://camppowercalc.com/en/" rel="noopener noreferrer"&gt;https://camppowercalc.com/en/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>tools</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I built a tiny import-duty calculator because the official ones are a maze</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Thu, 16 Jul 2026 01:54:07 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-built-a-tiny-import-duty-calculator-because-the-official-ones-are-a-maze-3cb2</link>
      <guid>https://dev.to/chuanbuilds/i-built-a-tiny-import-duty-calculator-because-the-official-ones-are-a-maze-3cb2</guid>
      <description>&lt;p&gt;A few months ago a friend asked me to help figure out the tariff on a synthesizer he wanted to buy from a shop in Japan and ship to the US. Simple question, right? How much duty will this actually owe?&lt;/p&gt;

&lt;p&gt;Six tabs and an hour later, I still didn't have a clean answer. The official sources exist — they're just buried in HS-code tables written for customs brokers, not humans. You're expected to know that a "synthesizer" maps to a specific harmonized code, then cross-reference the MFN rate, then remember that the rate depends on where the thing was &lt;em&gt;made&lt;/em&gt;, not where you bought it.&lt;/p&gt;

&lt;p&gt;So I built the thing I wished existed: &lt;a href="https://tariffpedia.com" rel="noopener noreferrer"&gt;TariffPedia&lt;/a&gt;. You type a product name or paste an HS code, pick the destination (US, EU, UK, or China for now), and it shows the representative MFN duty rate with a link straight to the official government source behind each number. No account, no paywall, no "sign up to see the result."&lt;/p&gt;

&lt;p&gt;The part I cared about most was the source links. Anyone can quote a percentage; the useful thing is being one click from the page that actually says it, so you can verify before you rely on it. Last week I used it to sanity-check a camera lens I was importing, and the ten seconds it took beat the alternative of guessing and hoping the courier didn't slap on a surprise fee.&lt;/p&gt;

&lt;p&gt;One honest caveat: these are &lt;em&gt;representative&lt;/em&gt; MFN rates. The real number shifts with the product's country of origin, trade agreements, and the occasional exemption, and I'm not a customs broker. For anything with real money behind it, check the official source (TariffPedia links to it) or ask a licensed broker. I just wanted the guessing to stop for the small, everyday "wait, will this get taxed?" questions.&lt;/p&gt;

&lt;p&gt;If you've ever stared at a customs form wondering what number goes where, it's here: &lt;a href="https://tariffpedia.com" rel="noopener noreferrer"&gt;https://tariffpedia.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>fintech</category>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Digital Nomad Taxes: the basics before you panic</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Tue, 14 Jul 2026 01:05:56 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/digital-nomad-taxes-the-basics-before-you-panic-1i29</link>
      <guid>https://dev.to/chuanbuilds/digital-nomad-taxes-the-basics-before-you-panic-1i29</guid>
      <description>&lt;p&gt;Everyone's "just work from Bali" story skips the boring part: you probably still owe tax. Being a digital nomad is a lifestyle, not a tax category. Here's what actually matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where you're taxed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;US citizens&lt;/strong&gt; are taxed on worldwide income regardless of where they live.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most others&lt;/strong&gt; are taxed where they're a tax resident — commonly the 183-day rule.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Double-taxation treaties&lt;/strong&gt; exist between many countries so you're not charged twice, but you must actually claim them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Two levers US expats use
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Foreign Earned Income Exclusion (FEIE)&lt;/strong&gt; — excludes a chunk of earned income if you meet the residency test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Foreign Tax Credit&lt;/strong&gt; — offsets US tax by what you already paid abroad.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don't DIY the hard stuff
&lt;/h2&gt;

&lt;p&gt;If you've got income in three countries or a business structure, talk to someone. The cost of a mistake beats the cost of a consult.&lt;/p&gt;

&lt;p&gt;I keep the plain-language version and simple calculators at &lt;a href="https://taxedabroad.com/en/" rel="noopener noreferrer"&gt;Taxed Abroad&lt;/a&gt; — it's where I dump what I learn so I don't forget it. Use it to know which questions to ask, then confirm with a pro.&lt;/p&gt;

</description>
      <category>taxes</category>
      <category>digitalnomad</category>
      <category>expat</category>
      <category>indiehackers</category>
    </item>
    <item>
      <title>Two image tools I use that need zero install</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Mon, 13 Jul 2026 12:00:50 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/two-free-image-tools-i-use-that-need-zero-install-4mbk</link>
      <guid>https://dev.to/chuanbuilds/two-free-image-tools-i-use-that-need-zero-install-4mbk</guid>
      <description>&lt;p&gt;I edit a lot of images for the web and I got sick of heavy desktop apps and sketchy upload sites. Two browser tools ended up in my daily rotation:&lt;/p&gt;

&lt;h2&gt;
  
  
  CompactJPG — shrink images without losing the plot
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://compactjpg.com" rel="noopener noreferrer"&gt;CompactJPG&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Free online image compressor for JPG/PNG/WebP. The part I care about: it processes files locally in your browser, so nothing gets uploaded to some server. You drag in a photo, pick a level, and download a much smaller file that still looks fine. I use it before publishing any screenshot or product shot — shaves page weight without visible quality loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  ClarifyPix — fix an image with AI
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://clarifypix.com" rel="noopener noreferrer"&gt;ClarifyPix&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a photo is blurry, low-res, or has a messy background, ClarifyPix runs AI on it to upscale, deblur, remove the background, or touch it up. You upload the photo for processing (deleted after an hour), and there's no free tier — a $1.99/week trial covers short projects. Handy for ecommerce listings, profile pics, or old photos you want to rescue.&lt;/p&gt;




&lt;p&gt;Both are part of a small set of tools I keep at &lt;a href="https://untrackedtools.com/en/" rel="noopener noreferrer"&gt;Untracked Tools&lt;/a&gt;. CompactJPG is free with no account; ClarifyPix needs an account and a paid trial. If your workflow still involves opening Photoshop to crop a JPEG, try the compressor first — it'll save you five minutes a day.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>tools</category>
    </item>
    <item>
      <title>I shipped 8 small web tools for overseas users — here's the messy truth</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Sun, 12 Jul 2026 02:18:37 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/i-shipped-8-small-web-tools-for-overseas-users-heres-the-messy-truth-1051</link>
      <guid>https://dev.to/chuanbuilds/i-shipped-8-small-web-tools-for-overseas-users-heres-the-messy-truth-1051</guid>
      <description>&lt;p&gt;A while back I stopped waiting for the one big SaaS idea and started building a bunch of small, boring tools that each solve exactly one problem. The theory: a portfolio of tiny sites, each monetized with ads or a subscription, compounding traffic over months instead of betting everything on a launch.&lt;/p&gt;

&lt;p&gt;It's been equal parts fun and humbling. Here's what's live so far and what I actually learned shipping them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tools
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Images &amp;amp; AI&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://compactjpg.com/" rel="noopener noreferrer"&gt;CompactJPG&lt;/a&gt; — a free online image compressor. Files are processed locally in the browser, nothing gets uploaded, and it keeps quality better than I expected.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://clarifypix.com/" rel="noopener noreferrer"&gt;ClarifyPix&lt;/a&gt; — AI image fixes: upscale a blurry photo, remove a background, clean up an image. You upload a photo for processing (deleted after an hour); no free tier, but a $1.99/week trial.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Calculators (people love a good calculator)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://camppowercalc.com/en/" rel="noopener noreferrer"&gt;Camp Power Calc&lt;/a&gt; — type in your devices (fridge, lights, phone, rice cooker) and it tells you the total draw, battery size, and solar panel you need so you don't lose power mid-trip.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://roompaintcalc.com/en/" rel="noopener noreferrer"&gt;Room Paint Calculator&lt;/a&gt; — punch in room size, doors, windows and get liters of paint plus a rough cost.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://frycalc.com/" rel="noopener noreferrer"&gt;Fry Calc&lt;/a&gt; — temps, time, and oil for frying / air fryer based on ingredient and portion. Made it after one too many ruined batches.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://coldplungecalc.com/en/" rel="noopener noreferrer"&gt;Cold Plunge Calculator&lt;/a&gt; — dial in water temp, duration, and how much ice to add based on body weight and volume, so cold therapy stays safe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Collections &amp;amp; money&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://untrackedtools.com/en/" rel="noopener noreferrer"&gt;Untracked Tools&lt;/a&gt; — the hub that lists every small tool I build in one place. No ads, instant load.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://taxedabroad.com/" rel="noopener noreferrer"&gt;Taxed Abroad&lt;/a&gt; — tax guidance for expats and digital nomads: residency, treaties, filing obligations, in plain language.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;Specific beats clever.&lt;/strong&gt; "Camp power calculator" gets searched. "Smart outdoor energy platform" does not. I wasted a week on a clever name for the paint tool before renaming it to what people actually type.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribution is the real product.&lt;/strong&gt; Building took days; getting the first 100 visitors took longer. Submitting to directories, writing a few posts, and answering questions in the right places moved the needle more than any feature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Calculators quietly convert.&lt;/strong&gt; They're not flashy, but someone who just calculated their campsite battery need is a warm visitor. AdSense on these pages also performs better than on vague landing pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't fake the numbers.&lt;/strong&gt; Early on I was tempted to post MRR screenshots I didn't have. Didn't. The builders who share real, including ugly, numbers are the ones people trust and link to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this is going
&lt;/h2&gt;

&lt;p&gt;The plan is to keep shipping one focused tool at a time, link them together through &lt;a href="https://untrackedtools.com/en/" rel="noopener noreferrer"&gt;Untracked Tools&lt;/a&gt;, and let SEO + a few good backlinks do the slow work. No growth hacks, just consistent small bets.&lt;/p&gt;

&lt;p&gt;If you're building small tools too, the hub above is the easiest way to see everything in one spot. Happy to compare notes with anyone on the same path.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Image Compression for People Who Just Want Smaller Photos</title>
      <dc:creator>chuanbuilds</dc:creator>
      <pubDate>Sat, 16 May 2026 05:51:52 +0000</pubDate>
      <link>https://dev.to/chuanbuilds/image-compression-for-people-who-just-want-smaller-photos-30cn</link>
      <guid>https://dev.to/chuanbuilds/image-compression-for-people-who-just-want-smaller-photos-30cn</guid>
      <description>&lt;p&gt;Most email providers cap attachments at 20–25 MB (Gmail and Yahoo at 25 MB, Outlook at 20 MB). Modern iPhone photos typically range from 3 MB to 12 MB depending on mode, so a handful of attachments will hit the limit. The same problem appears everywhere: website uploads that reject large files, social media platforms that take forever to load your photos, cloud storage filling up faster than expected.&lt;/p&gt;

&lt;p&gt;The solution is image compression — making files smaller without making them look worse. Here's what you actually need to know, explained without jargon.&lt;/p&gt;

&lt;p&gt;Why Are My Photos So Large?&lt;br&gt;
A digital photo is a grid of pixels, and each pixel stores color information. A single photo from a modern smartphone might be 4032 × 3024 pixels — that's over 12 million pixels. Each pixel needs at least 3 bytes (one for red, green, and blue), so the raw data is around 36 MB before any compression.&lt;/p&gt;

&lt;p&gt;JPEG compression reduces this dramatically by discarding details that the human eye can't easily see. That 36 MB of raw data becomes a 3–6 MB JPEG. But even at 3 MB, a dozen photos will blow past most email limits.&lt;/p&gt;

&lt;p&gt;What Compression Actually Does&lt;br&gt;
Think of compression like summarizing a long document. A good summary preserves the key points while cutting the word count. Image compression does the same thing with visual information — it keeps the details that matter and simplifies or discards the ones that don't.&lt;/p&gt;

&lt;p&gt;When you set a JPEG to "quality 80" (the default in CompactJPG), you're telling the compressor: "keep 80% of the visual information that matters most." The result is a file that looks almost identical to the original but is 40–70% smaller.&lt;/p&gt;

&lt;p&gt;The Quality Sweet Spot&lt;br&gt;
There's a quality sweet spot for most photos: somewhere between 70 and 85. Below 70, you start to notice artifacts — blocky patches, color banding, and blurry edges. Above 85, you're paying a steep file-size penalty for improvements that are nearly invisible.&lt;/p&gt;

&lt;p&gt;Here's a rough guide:&lt;/p&gt;

&lt;p&gt;Quality 85–95: For photos you plan to print or edit further. Minimal quality loss, but files are still relatively large.&lt;br&gt;
Quality 70–85: The sweet spot for web, email, and social media. Files are 40–70% smaller than the original, and quality is excellent.&lt;br&gt;
Quality 50–70: For thumbnails or where file size is the top priority. Noticeable quality loss on close inspection, but fine for small images.&lt;br&gt;
Below 50: Only for extreme compression needs. Expect visible artifacts.&lt;br&gt;
PNG vs JPEG: Which Should You Use?&lt;br&gt;
The short answer: use JPEG for photos, PNG for graphics with text, logos, or screenshots.&lt;/p&gt;

&lt;p&gt;JPEG was designed for photographs — images with smooth color gradients and lots of detail. It's excellent at compressing these while keeping quality high.&lt;/p&gt;

&lt;p&gt;PNG was designed for images that need pixel-perfect clarity: logos with sharp edges, screenshots with text, or any image that needs transparency. PNG compression is lossless, meaning it never degrades quality, but it can't compress photos as efficiently as JPEG.&lt;/p&gt;

&lt;p&gt;For web images, this matters a lot. A photo saved as PNG might be 5× larger than the same photo saved as a quality-80 JPEG, with no visible quality difference.&lt;/p&gt;

&lt;p&gt;What About WebP?&lt;br&gt;
WebP is a newer format developed by Google that aims to be better than both JPEG and PNG. At the same quality level, WebP files are typically 25–35% smaller than JPEG. It also supports transparency like PNG.&lt;/p&gt;

&lt;p&gt;Today, all modern browsers support WebP, so it's a great choice for the web. CompactJPG can compress WebP images just like JPEG, using the same quality slider.&lt;/p&gt;

&lt;p&gt;The Easiest Way to Compress Images&lt;br&gt;
CompactJPG was built for exactly this use case. Here's how simple it is:&lt;/p&gt;

&lt;p&gt;Drop your images on the page — or click to browse, or paste from clipboard.&lt;br&gt;
Click Compress. That's it. The default quality (80) works for most images.&lt;br&gt;
Compare the result using the side-by-side view if you want to check quality.&lt;br&gt;
Download individual files or all at once as a ZIP.&lt;br&gt;
And here's the important part: your images never leave your device. Everything happens in your browser using WebAssembly technology. No uploads, no servers, no privacy concerns. Just smaller images.&lt;/p&gt;

&lt;p&gt;You can try the tool at &lt;a href="https://compactjpg.com" rel="noopener noreferrer"&gt;https://compactjpg.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
