<?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: Coloful Toolhub</title>
    <description>The latest articles on DEV Community by Coloful Toolhub (@colorfultoolhub).</description>
    <link>https://dev.to/colorfultoolhub</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%2F4121693%2Fd1311437-4ddd-4094-a859-9d2097702f2f.png</url>
      <title>DEV Community: Coloful Toolhub</title>
      <link>https://dev.to/colorfultoolhub</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/colorfultoolhub"/>
    <language>en</language>
    <item>
      <title>Developer Quick Fix: broken JSON, regex, HTML, and the lookup you actually need</title>
      <dc:creator>Coloful Toolhub</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:43:22 +0000</pubDate>
      <link>https://dev.to/colorfultoolhub/developer-quick-fix-broken-json-regex-html-and-the-lookup-you-actually-need-2g6c</link>
      <guid>https://dev.to/colorfultoolhub/developer-quick-fix-broken-json-regex-html-and-the-lookup-you-actually-need-2g6c</guid>
      <description>&lt;p&gt;There is no single page named Developer Quick Fix. This is a sequence through tools that already exist on &lt;a href="https://toolhub.snamibo.com/" rel="noopener noreferrer"&gt;Colorful Toolhub&lt;/a&gt; and run in the browser: a payload that will not parse, a regular expression that misses, HTML crushed onto one line, and a magic number you should not keep guessing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the JSON readable before you diff it
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/A/t/json-workbench" rel="noopener noreferrer"&gt;JSON Workbench&lt;/a&gt; can format, minify, escape, unescape, convert Unicode and Chinese punctuation, sort keys, inspect a tree, validate a schema, run JSONPath, compare documents, and draft models. Use that list in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check that it is JSON. If it is not, unescape first. Logs often wrap the payload in another string.&lt;/li&gt;
&lt;li&gt;Format only after it parses. Minify when you have to paste it back into a query or a string literal.&lt;/li&gt;
&lt;li&gt;Sort keys before a diff. Key order is not a content change.&lt;/li&gt;
&lt;li&gt;Pull one field with JSONPath instead of another chain of &lt;code&gt;data.data.list[0]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Treat generated models as a sketch of the shape. Rename fields before they land in the repo.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Decode &lt;code&gt;\uXXXX&lt;/code&gt; in the workbench instead of by hand. Convert full-width quotes and commas back to ASCII before blaming the parser for a quote that is not a quote.&lt;/p&gt;

&lt;h2&gt;
  
  
  Regex: look up the metacharacter, then generate, then test three strings
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/A/t/regex-metachar-reference" rel="noopener noreferrer"&gt;Regular Expression Metacharacter Reference&lt;/a&gt; covers escapes, classes, quantifiers, anchors, groups, lookaround, and JavaScript flags. Confirm the engine, and decide whether you need the &lt;code&gt;u&lt;/code&gt; flag. Without it, some Unicode classes do not match what you expect.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/A/t/regex-code-generator" rel="noopener noreferrer"&gt;Regex Code Generator&lt;/a&gt; drafts an expression and a language-specific call from a description. It does not know whether your input contains newlines, or whether you need a full match. Before you commit it, run three samples: one hit, one miss, and one boundary you meant to exclude, such as a trailing space or a full-width symbol.&lt;/p&gt;

&lt;p&gt;When the expression is right in a regex literal and wrong inside JSON, the extra backslash was eaten by another layer. The &lt;a href="https://toolhub.snamibo.com/A/t/js-escape-reference" rel="noopener noreferrer"&gt;JavaScript Escape Sequence Reference&lt;/a&gt; separates JS strings, JSON strings, template literals, and regex literals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Beautify HTML and CSS before you edit them
&lt;/h2&gt;

&lt;p&gt;Do not patch a minified line. The &lt;a href="https://toolhub.snamibo.com/R/t/css-html-formatter" rel="noopener noreferrer"&gt;CSS and HTML Formatter&lt;/a&gt; beautifies or minifies CSS, and beautifies, minifies, or escapes HTML. Beautify while debugging. Minify only when you are packaging. Escape when the snippet has to appear as text, so a &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; is not parsed as an element.&lt;/p&gt;

&lt;p&gt;For a real table, the &lt;a href="https://toolhub.snamibo.com/R/t/html-table-generator" rel="noopener noreferrer"&gt;HTML Table Generator&lt;/a&gt; turns rows and columns into markup you can copy.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/H/t/text-quick-tools" rel="noopener noreferrer"&gt;Text Quick Tools&lt;/a&gt; join lines, or strip letters, CJK characters, or digits while leaving the rest. That is input cleanup, not redaction. Do not "remove digits" and call a secret safe.&lt;/p&gt;

&lt;h2&gt;
  
  
  Look up the constant, then write the name back
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/TT/t/developer-cheat-sheet-reference" rel="noopener noreferrer"&gt;Developer Cheat Sheet Reference&lt;/a&gt; covers Android Manifest permissions, editor shortcuts, User-Agent examples, and HTML, CSS, JavaScript, and DOM. Narrower tables are faster when you already know the question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Key codes and &lt;code&gt;adb shell input keyevent&lt;/code&gt;: &lt;a href="https://toolhub.snamibo.com/TT/t/android-keyevent-reference" rel="noopener noreferrer"&gt;Android KeyEvent reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Named, decimal, and hex entities: &lt;a href="https://toolhub.snamibo.com/TT/t/html-entity-reference" rel="noopener noreferrer"&gt;HTML entity reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Extension to &lt;code&gt;Content-Type&lt;/code&gt;: &lt;a href="https://toolhub.snamibo.com/A/t/mime-type-reference" rel="noopener noreferrer"&gt;MIME type reference&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The English name of a keyboard glyph: &lt;a href="https://toolhub.snamibo.com/TT/t/keyboard-symbol-reference" rel="noopener noreferrer"&gt;keyboard symbol reference&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are references, not the spec. Recheck permissions and key codes against the SDK you ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  One order, so you do not change three layers at once
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Parse the payload, sort keys, and keep a copy.&lt;/li&gt;
&lt;li&gt;If the failure is a match, check metacharacters and escape layers, draft with the generator, and test three strings.&lt;/li&gt;
&lt;li&gt;If the failure is layout, beautify, then edit.&lt;/li&gt;
&lt;li&gt;If the failure is a magic number, look it up and put the constant name in the code.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;General utilities: &lt;a href="https://toolhub.snamibo.com/A" rel="noopener noreferrer"&gt;Developer General Utilities&lt;/a&gt;. Formatting: &lt;a href="https://toolhub.snamibo.com/R" rel="noopener noreferrer"&gt;Frontend Devtools&lt;/a&gt;. Sheets: &lt;a href="https://toolhub.snamibo.com/TT" rel="noopener noreferrer"&gt;Tool Aggregation Nav&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The smallest SEO loop for a static tool site</title>
      <dc:creator>Coloful Toolhub</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:41:44 +0000</pubDate>
      <link>https://dev.to/colorfultoolhub/the-smallest-seo-loop-for-a-static-tool-site-4m66</link>
      <guid>https://dev.to/colorfultoolhub/the-smallest-seo-loop-for-a-static-tool-site-4m66</guid>
      <description>&lt;p&gt;Tool sites generate many similar URLs. The pieces below are the ones that change indexing and share cards. Examples are taken from the public HTML of &lt;a href="https://toolhub.snamibo.com/" rel="noopener noreferrer"&gt;Colorful Toolhub&lt;/a&gt;. The generators live on the &lt;a href="https://toolhub.snamibo.com/Q" rel="noopener noreferrer"&gt;SEO Marketing workbench&lt;/a&gt; and run in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  One title and description per URL
&lt;/h2&gt;

&lt;p&gt;The home page title is "Colorful Toolhub by Snamibo - Free Online Tools Collection", and the description names 1,400+ tools, 72 workbenches, and local processing. A category page should not repeat that sentence. &lt;a href="https://toolhub.snamibo.com/P4G" rel="noopener noreferrer"&gt;Mobile PWA Tools&lt;/a&gt; is titled "Mobile PWA Tools - Free Online Tools" and names Compass and the PWA Manifest Generator. That difference is what a search snippet is for.&lt;/p&gt;

&lt;p&gt;Keep titles near 60 English characters, with the page topic before the brand. Keep descriptions near 150–160 characters. If you leave the description empty, the engine will quote navigation or a random tool name.&lt;/p&gt;

&lt;p&gt;Every indexable URL needs one &lt;code&gt;rel=canonical&lt;/code&gt; to the URL you want indexed. Search URLs such as &lt;code&gt;/?q=&lt;/code&gt; should canonicalize back to the stable page, not spawn an index entry per query.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/Q/t/meta-tag-generator" rel="noopener noreferrer"&gt;Meta Tag Generator&lt;/a&gt; emits title, description, canonical, and viewport together. Viewport is not a ranking hint, but a missing viewport is treated as a poor mobile page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Graph is the share card, not the ranking
&lt;/h2&gt;

&lt;p&gt;The home page sets &lt;code&gt;og:type=website&lt;/code&gt; and &lt;code&gt;og:image&lt;/code&gt; to &lt;code&gt;https://toolhub.snamibo.com/og-toolhub.png&lt;/code&gt; at 1200×630. Use an absolute image URL. Relative paths often become a blank card in chat apps.&lt;/p&gt;

&lt;p&gt;Also set &lt;code&gt;twitter:card&lt;/code&gt; to &lt;code&gt;summary_large_image&lt;/code&gt; with the same image. Not every crawler falls back from Open Graph to Twitter or the other way around.&lt;/p&gt;

&lt;p&gt;Generate tags with the &lt;a href="https://toolhub.snamibo.com/Q/t/open-graph-generator" rel="noopener noreferrer"&gt;Open Graph Generator&lt;/a&gt;, then check truncation in the &lt;a href="https://toolhub.snamibo.com/Q/t/open-graph-preview" rel="noopener noreferrer"&gt;Open Graph Preview&lt;/a&gt;. After deploy, refresh the platform's own cache. A correct tag can still show the previous card for days.&lt;/p&gt;

&lt;h2&gt;
  
  
  hreflang has to be a closed set
&lt;/h2&gt;

&lt;p&gt;The home page announces &lt;code&gt;og:locale=en_US&lt;/code&gt;, &lt;code&gt;og:locale:alternate=zh_CN&lt;/code&gt;, and JSON-LD &lt;code&gt;inLanguage&lt;/code&gt; of &lt;code&gt;en-US&lt;/code&gt; and &lt;code&gt;zh-CN&lt;/code&gt;. That does not replace hreflang.&lt;/p&gt;

&lt;p&gt;Each language URL needs the full set, including itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://toolhub.snamibo.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"zh-CN"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://toolhub.snamibo.com/zh/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"alternate"&lt;/span&gt; &lt;span class="na"&gt;hreflang=&lt;/span&gt;&lt;span class="s"&gt;"x-default"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://toolhub.snamibo.com/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Chinese page needs the same three lines. A one-sided annotation is ignored. &lt;code&gt;x-default&lt;/code&gt; is for visitors who match neither language. Build the set with the &lt;a href="https://toolhub.snamibo.com/Q/t/hreflang-generator" rel="noopener noreferrer"&gt;Hreflang Generator&lt;/a&gt; so the self-reference is not the line you forget.&lt;/p&gt;

&lt;h2&gt;
  
  
  robots.txt and the sitemap describe only URLs you can stand behind
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;robots.txt&lt;/code&gt; belongs at the origin root. Allow CSS and JavaScript. A &lt;code&gt;Disallow: /&lt;/code&gt; cannot be undone by a &lt;code&gt;noindex&lt;/code&gt; the crawler is not allowed to fetch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight apache"&gt;&lt;code&gt;&lt;span class="nc"&gt;User&lt;/span&gt;-agent: *
&lt;span class="nc"&gt;Allow&lt;/span&gt;: /

Sitemap: https://toolhub.snamibo.com/sitemap.xml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write it in the &lt;a href="https://toolhub.snamibo.com/Q/t/robots-txt-generator" rel="noopener noreferrer"&gt;Robots.txt Generator&lt;/a&gt; and probe real paths in the &lt;a href="https://toolhub.snamibo.com/Q/t/robots-txt-tester" rel="noopener noreferrer"&gt;Robots.txt Tester&lt;/a&gt;: home, one category, one draft you intend to hide.&lt;/p&gt;

&lt;p&gt;A sitemap should list only 200 OK, indexable, canonical URLs. Leave out site search and session parameters. &lt;code&gt;changefreq&lt;/code&gt; and &lt;code&gt;priority&lt;/code&gt; are mostly ignored. Generate XML with the &lt;a href="https://toolhub.snamibo.com/Q/t/sitemap-generator" rel="noopener noreferrer"&gt;Sitemap Generator&lt;/a&gt;, then drop 404s with the &lt;a href="https://toolhub.snamibo.com/Q/t/dead-link-checker" rel="noopener noreferrer"&gt;Dead Link Checker&lt;/a&gt;. A dead URL inside a sitemap is worse than no sitemap, because you handed the crawler the broken address.&lt;/p&gt;

&lt;h2&gt;
  
  
  JSON-LD only for what the page really does
&lt;/h2&gt;

&lt;p&gt;The home page's JSON-LD is a &lt;code&gt;WebSite&lt;/code&gt; plus an &lt;code&gt;Organization&lt;/code&gt;. The site declares a &lt;code&gt;SearchAction&lt;/code&gt; targeting &lt;code&gt;https://toolhub.snamibo.com/?q={search_term_string}&lt;/code&gt;. Keep that only if the query string actually searches. A client-side filter that ignores the parameter on reload should not advertise a search action.&lt;/p&gt;

&lt;p&gt;A tool page fits &lt;code&gt;WebApplication&lt;/code&gt; better than a fake review snippet. Do not invent ratings. Draft with the &lt;a href="https://toolhub.snamibo.com/Q/t/schema-jsonld-generator" rel="noopener noreferrer"&gt;Schema.org JSON-LD Generator&lt;/a&gt; and check required fields in Rich Results Test. A pass means the markup is well formed, not that Google will show a rich result.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep campaign parameters off the canonical URL
&lt;/h2&gt;

&lt;p&gt;Build campaign links with the &lt;a href="https://toolhub.snamibo.com/Q/t/tracking-url-builder" rel="noopener noreferrer"&gt;Tracking URL Builder&lt;/a&gt;. Canonicals and sitemap URLs stay clean. Otherwise one article becomes a pile of indexed parameter variants.&lt;/p&gt;

&lt;p&gt;That loop is the whole controllable base for a static tool site that does not yet have an editorial blog: unique titles, canonicals, a 1200×630 share image, paired hreflang, a root robots file, a sitemap of live URLs, and JSON-LD that matches the page.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>seo</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Ship an installable PWA: manifest, maskable icons, and a service worker</title>
      <dc:creator>Coloful Toolhub</dc:creator>
      <pubDate>Sat, 03 Oct 2026 15:40:17 +0000</pubDate>
      <link>https://dev.to/colorfultoolhub/ship-an-installable-pwa-manifest-maskable-icons-and-a-service-worker-18bh</link>
      <guid>https://dev.to/colorfultoolhub/ship-an-installable-pwa-manifest-maskable-icons-and-a-service-worker-18bh</guid>
      <description>&lt;p&gt;This is the short path that actually makes a static site installable. The generators used below run locally in the browser on &lt;a href="https://toolhub.snamibo.com/P4G" rel="noopener noreferrer"&gt;Colorful Toolhub's Mobile PWA workbench&lt;/a&gt;. You still deploy the files yourself.&lt;/p&gt;

&lt;p&gt;Chromium installs a site when it is served over HTTPS, the page points at a valid manifest, a service worker controls the page, and 192px and 512px icons are present. iOS does not use the manifest icons for the home screen. You still need &lt;code&gt;apple-touch-icon&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Manifest
&lt;/h2&gt;

&lt;p&gt;Use the &lt;a href="https://toolhub.snamibo.com/P4G/t/manifest" rel="noopener noreferrer"&gt;PWA Manifest Generator&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;short_name&lt;/code&gt; stays around 12 characters. Home screens truncate longer names.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;start_url&lt;/code&gt; is a stable path inside the site, optionally with one fixed query such as &lt;code&gt;/?source=pwa&lt;/code&gt;. Do not put changing analytics parameters here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scope&lt;/code&gt; must cover &lt;code&gt;start_url&lt;/code&gt;. A site deployed at &lt;code&gt;/app/&lt;/code&gt; cannot use scope &lt;code&gt;/&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;display: "standalone"&lt;/code&gt; is the usual choice. &lt;code&gt;browser&lt;/code&gt; does not leave the browser UI. &lt;code&gt;fullscreen&lt;/code&gt; hides the status bar.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;background_color&lt;/code&gt; is the splash background. &lt;code&gt;theme_color&lt;/code&gt; is the browser chrome. They can differ.&lt;/li&gt;
&lt;li&gt;Provide PNG icons at 192 and 512. SVG alone is still unreliable on some Android installers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;shortcuts&lt;/code&gt; are optional. Each shortcut URL has to sit inside &lt;code&gt;scope&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Save the file as &lt;code&gt;/manifest.json&lt;/code&gt; and add this to every HTML document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"manifest"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/manifest.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A root-relative href that does not match the deployed path fails silently. The installer requests that exact URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Maskable icons
&lt;/h2&gt;

&lt;p&gt;Android masks icons as a circle, a rounded square, or a teardrop. The safe zone is roughly the center 80%. Keep the mark inside that circle.&lt;/p&gt;

&lt;p&gt;Adjust it in the &lt;a href="https://toolhub.snamibo.com/P4G/t/maskable" rel="noopener noreferrer"&gt;Maskable Icon Editor&lt;/a&gt;, and preview circle, rounded-rect, and teardrop. Prefer two manifest entries over a single &lt;code&gt;purpose: "any maskable"&lt;/code&gt; image:&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;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/icon-192.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192x192"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"purpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"any"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&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;"src"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/icon-maskable-192.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"sizes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192x192"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"purpose"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"maskable"&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;Do the same for 512. One image marked &lt;code&gt;any maskable&lt;/code&gt; is often padded, so the non-masked icon looks small.&lt;/p&gt;

&lt;p&gt;iOS still wants touch icons and splash screens. The &lt;a href="https://toolhub.snamibo.com/P4G/t/launch-icon" rel="noopener noreferrer"&gt;Launch Icon and Splash Generator&lt;/a&gt; exports those PNGs and the link tags. Without them, Safari screenshots the current page and flashes a blank splash.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service worker
&lt;/h2&gt;

&lt;p&gt;Installability only needs a controlling worker. Caching strategy decides whether the next deploy is reachable.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fingerprinted JS, CSS, and fonts: cache-first. A new filename is a new resource.&lt;/li&gt;
&lt;li&gt;HTML: network-first, then cache. Cache-first HTML keeps pointing at deleted hashed assets and the site goes blank.&lt;/li&gt;
&lt;li&gt;API responses: stale-while-revalidate, or do not cache them.&lt;/li&gt;
&lt;li&gt;One offline fallback document for failed navigations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://toolhub.snamibo.com/P4G/t/service-worker" rel="noopener noreferrer"&gt;Service Worker Generator&lt;/a&gt; emits &lt;code&gt;sw.js&lt;/code&gt; plus a registration snippet for those strategies. Register after load. The default scope is the script's directory, so &lt;code&gt;/sw.js&lt;/code&gt; can control the origin and &lt;code&gt;/assets/sw.js&lt;/code&gt; cannot.&lt;/p&gt;

&lt;p&gt;Do not call &lt;code&gt;skipWaiting()&lt;/code&gt; and &lt;code&gt;clients.claim()&lt;/code&gt; on the first install of every version. The old page and the new cache will mix. Let the new worker wait, tell the page, and skip waiting only after a refresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check
&lt;/h2&gt;

&lt;p&gt;In Chrome DevTools, Application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manifest shows no errors, &lt;code&gt;start_url&lt;/code&gt; is inside &lt;code&gt;scope&lt;/code&gt;, icons preview.&lt;/li&gt;
&lt;li&gt;The service worker is activated and controls the current window.&lt;/li&gt;
&lt;li&gt;Offline reload still serves the HTML fallback you wrote, not the browser's offline dinosaur.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The install icon, or a firing &lt;code&gt;beforeinstallprompt&lt;/code&gt;, is the real signal. Lighthouse no longer scores PWA as a single category, so an old PWA score is not the definition of done.&lt;/p&gt;

</description>
      <category>pwa</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I built a free, local-first toolbox so I could stop opening five random sites</title>
      <dc:creator>Coloful Toolhub</dc:creator>
      <pubDate>Sat, 12 Sep 2026 05:10:12 +0000</pubDate>
      <link>https://dev.to/colorfultoolhub/i-built-a-free-local-first-toolbox-so-i-could-stop-opening-five-random-sites-4kbi</link>
      <guid>https://dev.to/colorfultoolhub/i-built-a-free-local-first-toolbox-so-i-could-stop-opening-five-random-sites-4kbi</guid>
      <description>&lt;p&gt;I got tired of opening a different website for every tiny job — format JSON, make a QR code, OCR a screenshot, convert YAML to JSON — and half of them wanted an account.&lt;/p&gt;

&lt;p&gt;So I put together Colorful Toolhub: a free collection of browser-based utilities. No signup. Where it makes sense, processing stays in the browser.&lt;/p&gt;

&lt;p&gt;Site: &lt;a href="https://toolhub.snamibo.com" rel="noopener noreferrer"&gt;https://toolhub.snamibo.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you only try a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JSON workbench: &lt;a href="https://toolhub.snamibo.com/A/t/json-workbench" rel="noopener noreferrer"&gt;https://toolhub.snamibo.com/A/t/json-workbench&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;QR generator: &lt;a href="https://toolhub.snamibo.com/T/t/qr-generator" rel="noopener noreferrer"&gt;https://toolhub.snamibo.com/T/t/qr-generator&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Image OCR (in-browser): &lt;a href="https://toolhub.snamibo.com/P4A/t/ocr" rel="noopener noreferrer"&gt;https://toolhub.snamibo.com/P4A/t/ocr&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;JSON/YAML/TOML/XML/CSV converter: &lt;a href="https://toolhub.snamibo.com/N/t/data-format-converter" rel="noopener noreferrer"&gt;https://toolhub.snamibo.com/N/t/data-format-converter&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About 1,450 tools across 72 workbenches, English and Chinese. I'm a solo builder; feedback on which tools are actually worth keeping in the front is welcome.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>privacy</category>
      <category>tooling</category>
    </item>
  </channel>
</rss>
