<?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: xiazai77</title>
    <description>The latest articles on DEV Community by xiazai77 (@xiazai77).</description>
    <link>https://dev.to/xiazai77</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%2F3818314%2F860a70cc-1fb6-47c1-b208-3d58fc01a987.png</url>
      <title>DEV Community: xiazai77</title>
      <link>https://dev.to/xiazai77</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xiazai77"/>
    <language>en</language>
    <item>
      <title>Building a Game Wiki: Heartopia.live Tech Stack</title>
      <dc:creator>xiazai77</dc:creator>
      <pubDate>Mon, 13 Apr 2026 12:26:23 +0000</pubDate>
      <link>https://dev.to/xiazai77/building-a-game-wiki-heartopialive-tech-stack-293m</link>
      <guid>https://dev.to/xiazai77/building-a-game-wiki-heartopialive-tech-stack-293m</guid>
      <description>&lt;p&gt;I built a game wiki for Heartopia — a cozy life sim that blew up earlier this year — and wanted to share the tech decisions behind it. Not because the stack is groundbreaking, but because building a game wiki has constraints that don't apply to typical web projects, and the choices I made were driven by those constraints.&lt;/p&gt;

&lt;p&gt;The site is &lt;a href="https://www.heartopia.live/en/" rel="noopener noreferrer"&gt;Heartopia.live&lt;/a&gt;. It covers codes, recipes, characters, an interactive world map, collection tracking, and event guides across 8 languages. Here's what powers it and why.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Static Export
&lt;/h2&gt;

&lt;p&gt;The single most important decision: &lt;strong&gt;Next.js with static export&lt;/strong&gt; (&lt;code&gt;output: 'export'&lt;/code&gt;). No server. No serverless functions. Just HTML, CSS, and JS files deployed to a CDN.&lt;/p&gt;

&lt;p&gt;Why? Game wikis have a specific traffic pattern. When a new update drops or an event starts, traffic spikes hard — sometimes 10x normal volume — for 48 hours, then drops back down. A server-based setup means either paying for capacity you don't need 95% of the time, or scrambling to scale during spikes.&lt;/p&gt;

&lt;p&gt;Static files on a CDN handle traffic spikes for free. Cloudflare Pages serves the whole site. Zero cold starts, zero scaling concerns, near-zero cost. The trade-off is no server-side logic, but for a wiki that's mostly read-heavy content, it's the right call.&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;// next.config.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&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;export&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;trailingSlash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;images&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;unoptimized&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&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;The &lt;code&gt;trailingSlash: true&lt;/code&gt; is for clean URLs on static hosting. &lt;code&gt;images.unoptimized&lt;/code&gt; because Next.js image optimization requires a server — with static export you handle images yourself.&lt;/p&gt;

&lt;p&gt;One nuance: I only enable &lt;code&gt;output: 'export'&lt;/code&gt; in production. During development, keeping it dynamic means proper 404 handling and HMR work normally. Caught this the hard way after wondering why dev mode was broken.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next.js 14 + React 18
&lt;/h2&gt;

&lt;p&gt;Nothing fancy here. App Router, TypeScript, standard file-based routing. The &lt;code&gt;[lang]&lt;/code&gt; dynamic segment handles i18n:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/app/[lang]/codes/page.tsx
src/app/[lang]/recipes/page.tsx
src/app/[lang]/world-map/page.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each page gets the language from the URL parameter and loads the corresponding translation file. No i18n library — just JSON files and a &lt;code&gt;getDictionary()&lt;/code&gt; function. For a site with mostly static content, this is simpler than setting up next-intl or similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  8 Languages Without an i18n Library
&lt;/h2&gt;

&lt;p&gt;The site supports English, Chinese, Thai, Portuguese, Indonesian, Spanish, French, and German. I went back and forth on whether to use an i18n framework and decided against it.&lt;/p&gt;

&lt;p&gt;The approach: one JSON file per language, loaded at build time. Each page calls &lt;code&gt;getDictionary(lang)&lt;/code&gt; which returns the typed translation object. TypeScript catches missing keys at compile time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Simplified version&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dictionaries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;en&lt;/span&gt;&lt;span class="p"&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./locales/en.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;zh&lt;/span&gt;&lt;span class="p"&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./locales/zh.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="na"&gt;th&lt;/span&gt;&lt;span class="p"&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./locales/th.json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getDictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&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;dictionaries&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For translation itself, I use LLM translation directly — no scripts, no regex replacement. Read the source file, translate the full content, write the target file. It's more accurate than automated pipelines for game-specific terminology.&lt;/p&gt;

&lt;p&gt;The rule I enforce: &lt;strong&gt;no hardcoded language checks anywhere in components&lt;/strong&gt;. No &lt;code&gt;lang === 'en' ? 'Save' : '保存'&lt;/code&gt;. Every UI string comes from the dictionary. This makes adding a new language a matter of adding one JSON file instead of touching every component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Architecture
&lt;/h2&gt;

&lt;p&gt;Game wiki data changes on a different cadence than the site code. New codes drop daily. Recipes and characters change with game updates. Event content is seasonal.&lt;/p&gt;

&lt;p&gt;I keep game data in separate JSON/TS files in a &lt;code&gt;data/&lt;/code&gt; directory, not in a CMS or database. For a statically exported site, this means data changes require a rebuild, but the build takes under 30 seconds so it's fine. A GitHub push triggers a Cloudflare Pages build automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;src/lib/data.ts          // Data loading utilities
src/data/codes.json      // Gift codes (updated frequently)
src/data/recipes.json    // Cooking recipes
src/data/characters.json // NPC data
src/data/fish.json       // Fish collection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The alternative was a headless CMS, but for a solo-maintained wiki where I'm the only editor, JSON files in a repo are faster to update than any CMS dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Interactive World Map
&lt;/h2&gt;

&lt;p&gt;The world map page is the most complex component. Players use it to find fish spawns, bug locations, forageable items, and more. It needs to be filterable, zoomable, and fast.&lt;/p&gt;

&lt;p&gt;I went with a custom implementation using CSS transforms for pan/zoom rather than pulling in Leaflet or MapLibre. The game map is a single large image (not tiles), so a full mapping library would be overkill. Custom markers are positioned with percentage-based coordinates relative to the map image.&lt;/p&gt;

&lt;p&gt;The filter system lets users toggle categories on and off — show only fish, show only bugs, etc. State is managed with React useState, no external state library needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collection Tracker
&lt;/h2&gt;

&lt;p&gt;The tracker lets players check off items they've found across 7 categories (fish, bugs, birds, crops, flowers, forageables, wild animals). Progress is saved to localStorage.&lt;/p&gt;

&lt;p&gt;Simple but effective. No auth required, no server storage, works offline. The main UX challenge was making 200+ checkboxes across 7 tabs not feel overwhelming — solved with search, category filters, and a progress bar per category.&lt;/p&gt;

&lt;h2&gt;
  
  
  Styling
&lt;/h2&gt;

&lt;p&gt;Tailwind CSS. No component library. For a content-heavy wiki, custom styling is faster than fighting a component library's opinions about how things should look. Tailwind's utility classes make responsive design straightforward, and the built-in dark mode toggle was trivial to implement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deployment
&lt;/h2&gt;

&lt;p&gt;Cloudflare Pages. Push to main → automatic build → deploy to global CDN. SSL, custom domain, and edge caching are all handled automatically. Cost: $0 on the free tier, which handles the traffic levels a game wiki gets.&lt;/p&gt;

&lt;p&gt;The deploy pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push origin main
→ Cloudflare Pages detects push
→ Runs &lt;span class="sb"&gt;`&lt;/span&gt;npm run build&lt;span class="sb"&gt;`&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;Next.js static &lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
→ Deploys /out directory to CDN
→ Live &lt;span class="k"&gt;in&lt;/span&gt; ~60 seconds
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SEO Considerations
&lt;/h2&gt;

&lt;p&gt;Game wikis live and die by search traffic. A few things that matter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trailing slashes and consistent URLs.&lt;/strong&gt; Pick one format and stick with it. &lt;code&gt;trailingSlash: true&lt;/code&gt; in Next.js config ensures every URL ends with &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Proper hreflang tags.&lt;/strong&gt; With 8 languages, search engines need to know which version to show which users. Each page generates &lt;code&gt;&amp;lt;link rel="alternate" hreflang="xx"&amp;gt;&lt;/code&gt; tags for all language variants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dynamic meta tags.&lt;/strong&gt; Every page has unique title and description pulled from the translation files. No hardcoded English meta tags on non-English pages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sitemap generation.&lt;/strong&gt; &lt;code&gt;src/app/sitemap.ts&lt;/code&gt; generates a sitemap with all pages across all languages. This is critical for getting non-English pages indexed.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'd Do Differently
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Start with fewer languages.&lt;/strong&gt; I launched with 8 and maintaining translations across all of them for every content update is time-consuming. Starting with 2-3 and adding more based on actual traffic data would have been smarter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Add search earlier.&lt;/strong&gt; A wiki without search is frustrating once it passes ~20 pages. I added it later and it immediately became one of the most-used features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Track data freshness.&lt;/strong&gt; Codes expire, events end, game mechanics change. I don't have a great system for flagging stale content yet. Something like a &lt;code&gt;lastVerified&lt;/code&gt; date per data entry would help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Numbers
&lt;/h2&gt;

&lt;p&gt;The whole thing runs on: Next.js 14, React 18, TypeScript, Tailwind CSS, Cloudflare Pages. No database, no CMS, no auth, no server. Build time under 30 seconds. Monthly hosting cost: $0.&lt;/p&gt;

&lt;p&gt;For a game wiki that needs to be fast, handle traffic spikes, support multiple languages, and be easy to update solo — this stack does the job. Nothing clever, nothing trendy. Just the right tool for each specific constraint.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>webdev</category>
      <category>wiki</category>
    </item>
    <item>
      <title>I Built 41 Free Browser-Based Developer Tools — Everything Runs Client-Side</title>
      <dc:creator>xiazai77</dc:creator>
      <pubDate>Wed, 11 Mar 2026 15:11:29 +0000</pubDate>
      <link>https://dev.to/xiazai77/i-built-41-free-browser-based-developer-tools-everything-runs-client-side-5hi5</link>
      <guid>https://dev.to/xiazai77/i-built-41-free-browser-based-developer-tools-everything-runs-client-side-5hi5</guid>
      <description>&lt;p&gt;Last year I got frustrated.&lt;/p&gt;

&lt;p&gt;I was debugging a JWT at 2am (classic), and the first three "free JWT decoders" I found all wanted me to create an account. The fourth one worked but pasted my token into some analytics endpoint — I spotted it in DevTools. Cool. Love that for me.&lt;/p&gt;

&lt;p&gt;So I built my own. And then I kept going.&lt;/p&gt;

&lt;p&gt;41 tools later, here's &lt;a href="https://purekit.dev" rel="noopener noreferrer"&gt;PureKit&lt;/a&gt; — a collection of browser-based developer tools where your data literally never leaves your machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;Here's my problem with most online dev tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;"Free" with an asterisk.&lt;/strong&gt; Free until you hit a daily limit, need to remove a watermark, or want to process more than one file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Uploading sensitive data to random servers.&lt;/strong&gt; I've seen JWT decoders that send your token to their backend. PDF tools that upload your documents to process them "in the cloud." No thanks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Account walls everywhere.&lt;/strong&gt; I just want to format some JSON. I don't need a relationship with your product.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted tools that are actually free, actually private, and just work when you open them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tech
&lt;/h2&gt;

&lt;p&gt;The whole thing is built with &lt;strong&gt;Next.js&lt;/strong&gt; and deployed on &lt;strong&gt;Cloudflare Pages&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The core principle: &lt;strong&gt;everything happens in the browser&lt;/strong&gt;. No file uploads to servers, no API calls with your data. When you paste JSON, it gets formatted in your browser tab. When you compress an image, the Canvas API and Web Workers handle it locally. Your files never touch my servers because there's nothing on my servers to touch them.&lt;/p&gt;

&lt;p&gt;Some specific tech decisions that might be useful if you're building something similar:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PDF processing&lt;/strong&gt; was the trickiest part. I'm using &lt;code&gt;pdf-lib&lt;/code&gt; and &lt;code&gt;pdf.js&lt;/code&gt; (Mozilla's library) running entirely client-side. Getting PDF merge to work without a backend took some wrestling — especially handling encrypted PDFs and different PDF versions. The gotcha: &lt;code&gt;pdf-lib&lt;/code&gt; can't render PDFs, and &lt;code&gt;pdf.js&lt;/code&gt; can't modify them, so you end up using both and bridging between their different document models. Not fun, but it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Image compression&lt;/strong&gt; uses the Canvas API to re-encode images. The trick is drawing the image to a canvas element and then exporting it with a lower quality setting via &lt;code&gt;canvas.toBlob()&lt;/code&gt;. For format conversion (say, PNG to WebP), same idea — draw to canvas, export as the target format. Web Workers keep the UI from freezing when you're processing large batches.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code formatting&lt;/strong&gt; (JSON, SQL, HTML, CSS, JS, XML) — I tried writing my own parser for JSON formatting at first. Don't do that. Just use Prettier for the code formatters and a proper SQL parser for SQL. I wasted two weekends on edge cases before I gave up and used battle-tested libraries. Sometimes the boring answer is the right one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Tools Worth Checking Out
&lt;/h2&gt;

&lt;p&gt;Here are the ones I use most myself:&lt;/p&gt;

&lt;h3&gt;
  
  
  🔍 JWT Decoder
&lt;/h3&gt;

&lt;p&gt;Paste a JWT, instantly see the header, payload, and signature. No server call — it's just base64 decoding in JavaScript. I built this one first because the existing options kept making me nervous about where my tokens were going.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/jwt-decoder/" rel="noopener noreferrer"&gt;purekit.dev/en/jwt-decoder&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📝 JSON Formatter
&lt;/h3&gt;

&lt;p&gt;Formats, validates, and lets you explore JSON with collapsible tree view. Handles big payloads without choking — I tested it with 50MB JSON files during development (my browser was less happy about that, but it worked).&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/json-formatter/" rel="noopener noreferrer"&gt;purekit.dev/en/json-formatter&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  📄 PDF Merge / Split / Compress
&lt;/h3&gt;

&lt;p&gt;This is the set I'm most proud of. Merge multiple PDFs, split pages out, or compress file size — all in the browser. Most "free" PDF tools either upload your files or limit you to 3 operations per day. These have no limits because there's no server cost per operation.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/pdf-merge/" rel="noopener noreferrer"&gt;purekit.dev/en/pdf-merge&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🖼️ Image Compressor &amp;amp; Format Converter
&lt;/h3&gt;

&lt;p&gt;Drop images in, get smaller files out. Supports JPEG, PNG, WebP. You can batch process multiple images and adjust quality. The format converter lets you go between formats — handy when you need WebP for the web but your designer gave you PNGs.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/image-compressor/" rel="noopener noreferrer"&gt;purekit.dev/en/image-compressor&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ⏰ Cron Expression Builder
&lt;/h3&gt;

&lt;p&gt;This one saves me every time I set up a scheduled job. Visual builder where you click what you want (every Monday at 9am, every 5 minutes, etc.) and it generates the cron expression. Also works in reverse — paste a cron expression and it tells you in plain English what it does.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/cron-expression-builder/" rel="noopener noreferrer"&gt;purekit.dev/en/cron-expression-builder&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🔤 Regex Tester
&lt;/h3&gt;

&lt;p&gt;Write regex, paste test strings, see matches highlighted in real time. Shows capture groups and explains what each part of your regex does. I know regex101 exists — I just wanted one that doesn't phone home with my test data.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/regex-tester/" rel="noopener noreferrer"&gt;purekit.dev/en/regex-tester&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  🎲 Mock Data Generator
&lt;/h3&gt;

&lt;p&gt;Generates fake JSON data based on a schema you define. Names, emails, addresses, dates, custom patterns. Useful when you need to seed a database or test an API but don't want to write a script for it.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://purekit.dev/en/mock-data-generator/" rel="noopener noreferrer"&gt;purekit.dev/en/mock-data-generator&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Full List
&lt;/h2&gt;

&lt;p&gt;Beyond those, there's a bunch more:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Formatters:&lt;/strong&gt; JSON, SQL, HTML, CSS, JavaScript, XML&lt;br&gt;
&lt;strong&gt;Encoders:&lt;/strong&gt; Base64, URL encode/decode&lt;br&gt;
&lt;strong&gt;Generators:&lt;/strong&gt; UUID, Hash (MD5/SHA), Password, Lorem Ipsum, QR Code, Favicon, Placeholder Images&lt;br&gt;
&lt;strong&gt;Converters:&lt;/strong&gt; Unix Timestamp, Color (HEX/RGB/HSL), YAML↔JSON↔TOML, JSON→CSV, Markdown↔HTML, HTML↔Markdown, Number Base, Image Format, Image→Base64, Image→PDF, PDF→Image, SVG→PNG&lt;br&gt;
&lt;strong&gt;Text Tools:&lt;/strong&gt; Case Converter, Word Counter, Diff Checker&lt;br&gt;
&lt;strong&gt;Data Tools:&lt;/strong&gt; CSV Cleaner, Mock Data Generator&lt;br&gt;
&lt;strong&gt;PDF Tools:&lt;/strong&gt; Merge, Split, Compress&lt;br&gt;
&lt;strong&gt;Encoders:&lt;/strong&gt; HTML Entity Encoder/Decoder&lt;/p&gt;

&lt;p&gt;41 tools and counting. I add new ones when I find myself googling "free online [thing]" for the third time.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Privacy
&lt;/h2&gt;

&lt;p&gt;I want to be straightforward about this: &lt;strong&gt;your data stays in your browser.&lt;/strong&gt; Period.&lt;/p&gt;

&lt;p&gt;There's no analytics tracking what you paste into the tools. There's no "we may share anonymized data" clause. The tools literally can't see your data because the processing happens in JavaScript on your machine.&lt;/p&gt;

&lt;p&gt;I built this the way I'd want a tool to work if I were the one pasting production JWT tokens or company documents into it. If I wouldn't trust a tool with my own data, I'm not going to ask anyone else to.&lt;/p&gt;

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

&lt;p&gt;I'm going to keep building more tools as I run into problems that need them. Some things I'm thinking about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API request tester (like a lightweight Postman in the browser)&lt;/li&gt;
&lt;li&gt;JSON schema validator&lt;/li&gt;
&lt;li&gt;SVG optimizer&lt;/li&gt;
&lt;li&gt;More code formatters (YAML, Markdown, etc.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there's a tool you wish existed as a simple browser-based utility, I'd genuinely like to hear about it. Drop a comment or hit me up.&lt;/p&gt;

&lt;p&gt;The whole thing is free and will stay free. No premium tier coming. No "upgrade to unlock" nonsense. Just tools.&lt;/p&gt;

&lt;p&gt;Check it out: &lt;strong&gt;&lt;a href="https://purekit.dev" rel="noopener noreferrer"&gt;purekit.dev&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thanks for reading. If you found this useful, a bookmark or a share goes a long way for a solo project like this. Happy coding.&lt;/em&gt;&lt;/p&gt;

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