← All tools tools.jamesking.io

tools.jamesking.io

A collection of small, single-purpose web tools, each built as a standalone, browser-based application. Deployed at tools.jamesking.io.

The guiding principles:

The only build step in the repo is build.js, which generates the landing page and the styled README pages. Individual tools never need compiling or bundling.

Repository structure

tools/
├── index.html              # GENERATED landing page (do not edit by hand)
├── build.js                # Generates index.html + README pages from each tool
├── README.md               # This file (rendered to /readme on the site)
├── netlify.toml            # Deploy config — runs `npm run build`
├── design-system/          # Shared tokens + components (see below)
│   ├── tokens.css
│   ├── components.css
│   └── index.html          # styleguide gallery
├── netlify/
│   └── edge-functions/     # e.g. rss-proxy.ts (CORS proxy for feeds)
└── <tool-name>/            # One folder per tool
    ├── index.html          # The tool (for hosted-here tools)
    └── README.md           # Tool docs (first heading + paragraph feed the index)

Adding a new tool

  1. Create a folder in the repo root named in kebab-case (e.g. pdf-merger/).

  2. Add index.html — your tool. Link the shared design system in the <head> (note the ../ — tools sit one level below the root):

    <link rel="stylesheet" href="../design-system/tokens.css">
    <link rel="stylesheet" href="../design-system/components.css">
    

    Then build the UI from the design-system classes (btn, card, field, badge, dialog, etc.). Keep only genuinely tool-specific layout in a small inline <style>, and reference tokens via hsl(var(--token)) so it tracks the theme. See syndicate-elsewhere/ for a worked example.

  3. Add README.md — must start with a level-1 heading and a short summary paragraph. These are extracted for the tool's card on the landing page:

    # PDF Merger
    
    Combine multiple PDFs into one, entirely in your browser.
    

    The full README is also rendered as a styled page at <tool>/readme.html.

  4. Rebuild so the landing page and README pages pick up the new tool:

    npm run build
    

Externally-hosted tools

If a tool lives elsewhere (another domain, an Apple Shortcut, etc.), it still gets a card — create a folder with just a README.md and add YAML frontmatter:

---
external: true
url: https://fonts.jamesking.io
---

# Font collection

A short description for the card.

The "Open Tool" button will link to url (opening in a new tab) instead of a local index.html.

Folders that are not tools

Shared infrastructure is excluded from the landing page via IGNORE_DIRS in build.js (currently design-system and netlify). Add to that set if you introduce more non-tool folders.

Development conventions

These are also recorded in CLAUDE.md for AI-assisted work.

Design system

A shared, no-build CSS layer keeps the tools visually consistent. It lives in design-system/:

File Purpose
tokens.css Design tokens as CSS custom properties — colors (HSL channel triplets), spacing, type, radii, shadows. Light / dark / system theming.
components.css Class-based components: btn, card, input/field, select, switch, badge, tabs, dialog, toast, table, prose, plus utilities.
index.html Living gallery of every token and component, with a light/dark toggle. Open this as the reference.

Theming is driven by data-theme on <html>:

Tools with a theme setting should resolve it in JS and set data-theme to light/dark.

Conventions: don't redefine component styles inside a tool — add only app-specific layout, and prefer a tool-scoped class over overriding a .btn/.card rule. When you add a new shared component, also add it to index.html. Full details in design-system/README.md.

Build & deploy

npm install        # one-time: install build/dev dependencies
npm run build      # generate index.html + all README pages
npm start          # serve locally (http-server) and open the index

build.js produces, from the project's README files:

All of these are generated artifacts and are gitignored (/index.html, /readme/, */readme.html) — never edit them by hand; edit the source README.md / build.js and rebuild.

Deployment: Netlify runs npm run build on deploy (see netlify.toml) and publishes the repo root, so the generated pages are always fresh. Edge functions in netlify/edge-functions/ are deployed alongside — e.g. rss-proxy.ts, a CORS proxy used by syndicate-elsewhere to fetch RSS feeds from the browser, and feed.ts, which serves a radio-archive-rss podcast feed encoded into its own URL.