Claude Code Plugins

Community-maintained marketplace

Feedback

simon-html-tools

@aborruso/ai-commons
0
0

Build single-file HTML tools following Simon Willison's patterns - self-contained HTML+JS+CSS applications optimized for LLM generation, no build step, CDN dependencies. Use when creating browser-based tools, utilities, or demos that should be (1) Self-contained in one HTML file, (2) Easy to distribute and host statically, (3) Quick to prototype with LLMs, (4) Client-side only with no server requirements. Ideal for data visualization, API explorers, format converters, debugging tools, and interactive demos.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name simon-html-tools
description Build single-file HTML tools following Simon Willison's patterns - self-contained HTML+JS+CSS applications optimized for LLM generation, no build step, CDN dependencies. Use when creating browser-based tools, utilities, or demos that should be (1) Self-contained in one HTML file, (2) Easy to distribute and host statically, (3) Quick to prototype with LLMs, (4) Client-side only with no server requirements. Ideal for data visualization, API explorers, format converters, debugging tools, and interactive demos.

Simon's HTML Tools

Build production-quality single-file HTML tools following patterns from Simon Willison's collection.

Core Philosophy

HTML tools are self-contained browser applications that:

  • Combine HTML, CSS, and JavaScript in a single file
  • Load dependencies from CDNs (no build step)
  • Can be copy-pasted from LLM responses
  • Host anywhere as static files
  • Remain small and maintainable (typically <500 lines)

Essential Principles

1. Single File, No Build Step

Always avoid React and build tools:

Prompt: "Build a JSON to YAML converter. No React."

Why no React:

  • JSX requires compilation
  • Slower to render in LLM environments
  • More prone to bugs
  • Harder to copy/paste and distribute

2. Load Dependencies from CDNs

Use version-pinned URLs from cdnjs.com or jsdelivr.com:

<script src="https://cdnjs.cloudflare.com/ajax/libs/js-yaml/4.1.0/js-yaml.min.js"></script>

3. Keep It Small

Target <500 lines total:

  • Easy for LLMs to understand and modify
  • Can be rewritten from scratch in minutes
  • Maintainability becomes less critical

Implementation Patterns

State Persistence in URL

Store application state in the URL for bookmarking and sharing:

// Save state to hash
function saveState(state) {
  window.location.hash = encodeURIComponent(JSON.stringify(state));
}

// Load state from hash
function loadState() {
  if (!window.location.hash) return null;
  try {
    return JSON.parse(decodeURIComponent(window.location.hash.slice(1)));
  } catch (e) {
    return null;
  }
}

Secrets in localStorage

Never put API keys in URLs or code. Use localStorage:

function getApiKey(serviceName) {
  const key = localStorage.getItem(`${serviceName}_api_key`);
  if (!key) {
    const newKey = prompt(`Enter your ${serviceName} API key:`);
    if (newKey) localStorage.setItem(`${serviceName}_api_key`, newKey);
    return newKey;
  }
  return key;
}

Advanced Clipboard Operations

document.addEventListener('paste', async (e) => {
  e.preventDefault();
  
  for (const item of e.clipboardData.items) {
    if (item.type.startsWith('image/')) {
      const file = item.getAsFile();
      // Handle image
    } else if (item.type === 'text/html') {
      const html = await new Promise(r => item.getAsString(r));
      // Handle HTML
    }
  }
});

// Copy to clipboard with fallback
async function copyToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
  } catch (err) {
    const textarea = document.createElement('textarea');
    textarea.value = text;
    textarea.style.position = 'fixed';
    textarea.style.opacity = '0';
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand('copy');
    document.body.removeChild(textarea);
  }
}

Working with Local Files

document.getElementById('fileInput').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  
  // Read as text
  const text = await file.text();
  
  // Or as Data URL
  const reader = new FileReader();
  reader.onload = (e) => processImage(e.target.result);
  reader.readAsDataURL(file);
});

Generate Downloadable Files

function downloadText(content, filename, mimeType = 'text/plain') {
  const blob = new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  a.click();
  URL.revokeObjectURL(url);
}

CORS-Enabled APIs

// PyPI
async function fetchPackage(name) {
  const res = await fetch(`https://pypi.org/pypi/${name}/json`);
  return await res.json();
}

// GitHub raw files
async function fetchGitHubFile(owner, repo, path) {
  const res = await fetch(
    `https://raw.githubusercontent.com/${owner}/${repo}/main/${path}`
  );
  return await res.text();
}

LLM API Direct Access

async function callClaude(prompt) {
  const apiKey = getApiKey('claude');
  const res = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': apiKey,
      'anthropic-version': '2023-06-01'
    },
    body: JSON.stringify({
      model: 'claude-3-haiku-20240307',
      max_tokens: 1024,
      messages: [{ role: 'user', content: prompt }]
    })
  });
  return await res.json();
}

Pyodide for Python

let pyodide = null;

async function initPyodide() {
  if (!pyodide) {
    pyodide = await loadPyodide();
    await pyodide.loadPackage(['numpy', 'pandas']);
  }
  return pyodide;
}

async function runPython(code) {
  const py = await initPyodide();
  return await py.runPythonAsync(code);
}

Template Structure

See references/template.md for complete HTML template with best practices.

Useful Libraries from CDN

Data Processing:

  • js-yaml, papaparse, jszip, dompurify

Visualization:

  • Chart.js, Plotly, Leaflet, highlight.js

File Processing:

  • PDF.js, Tesseract.js, exif-js, mammoth

Utilities:

  • date-fns, fuse.js, marked, diff

Hosting

Recommended: GitHub Pages

  1. Create repository
  2. Settings → Pages → Deploy from branch
  3. Copy HTML file
  4. Access at https://username.github.io/repo/tool.html

Avoid LLM platforms (restrictive sandboxes, warnings, less reliable)

Development Workflow

1. Prototype in Claude/ChatGPT

Build an artifact that converts CSV to JSON with preview. 
Use PapaParse from CDN. Add download button. No React.

2. Upgrade to Coding Agent

For complex projects: Claude Code or Codex CLI

3. Remix Existing Tools

Look at the pypi-changelog tool. Build a similar tool 
for npm packages showing version diffs.

Checklist

  • Single HTML file (no build step)
  • "No React" in prompts
  • CDN dependencies with versions
  • Code under 500 lines
  • Error handling for APIs
  • API keys in localStorage
  • State in URL or localStorage
  • Mobile responsive
  • Footer with source link

Resources

  • references/template.md - Complete HTML template structure
  • references/patterns.md - Detailed implementation patterns
  • references/libraries.md - Comprehensive CDN library catalog
  • references/examples.md - Real-world tool examples