import { useState, useEffect, useCallback, useRef } from "react"; const OCCUPATIONS = [ { key: "cm", label: "Computer & Mathematical", short: "Computer & Math" }, { key: "oa", label: "Office & Administrative Support", short: "Office & Admin" }, { key: "bf", label: "Business & Financial Operations", short: "Business & Finance" }, { key: "ad", label: "Arts, Design, Entertainment, Sports & Media", short: "Arts & Design" }, { key: "le", label: "Legal", short: "Legal" }, { key: "et", label: "Education, Training & Library", short: "Education & Library" }, { key: "mg", label: "Management", short: "Management" }, { key: "sc", label: "Life, Physical & Social Science", short: "Science" }, { key: "cs", label: "Community & Social Service", short: "Community & Social" }, { key: "hp", label: "Healthcare Practitioners & Technical", short: "Healthcare Practitioners" }, { key: "sr", label: "Sales & Related", short: "Sales" }, { key: "ae", label: "Architecture & Engineering", short: "Architecture & Eng." }, { key: "pc", label: "Personal Care & Service", short: "Personal Care" }, { key: "ps", label: "Protective Service", short: "Protective Service" }, { key: "hs", label: "Healthcare Support", short: "Healthcare Support" }, { key: "fp", label: "Food Preparation & Serving", short: "Food Prep & Serving" }, { key: "bg", label: "Building & Grounds Cleaning & Maintenance", short: "Building & Grounds" }, { key: "pr", label: "Production", short: "Production" }, { key: "ce", label: "Construction & Extraction", short: "Construction" }, { key: "tm", label: "Transportation & Material Moving", short: "Transportation" }, { key: "im", label: "Installation, Maintenance & Repair", short: "Install. & Repair" }, { key: "ff", label: "Farming, Fishing & Forestry", short: "Farming & Forestry" }, { key: "ts", label: "Technical SEO", short: "Technical SEO" }, { key: "fd", label: "Frontend Development", short: "Frontend Dev" }, { key: "om", label: "Online Marketing", short: "Online Marketing" }, { key: "lb", label: "Linkbuilding", short: "Linkbuilding" }, ]; const N = OCCUPATIONS.length; function generateRandom() { const vals = {}; OCCUPATIONS.forEach((o) => { vals[o.key] = Math.round(Math.random() * 10) * 10; }); return vals; } function encodeState(vals) { return OCCUPATIONS.map((o) => Math.round((vals[o.key] ?? 0) / 10)).join(""); } function decodeState(str) { const vals = {}; OCCUPATIONS.forEach((o, i) => { const ch = str[i]; vals[o.key] = ch !== undefined ? parseInt(ch, 10) * 10 : 0; if (isNaN(vals[o.key])) vals[o.key] = 0; vals[o.key] = Math.min(100, Math.max(0, vals[o.key])); }); return vals; } function getInitialValues() { try { const hash = window.location.hash.slice(1); if (hash && hash.length >= N && /^\d+$/.test(hash.slice(0, N))) return decodeState(hash); } catch (e) {} return generateRandom(); } const BG_DARK = "#111318"; const BG_CARD = "#1a1e26"; const BG_SLIDER = "#252a35"; const TEXT_PRIMARY = "#e4e7ec"; const TEXT_SECONDARY = "#8b93a5"; const TEXT_DIM = "#555d6e"; const ACCENT = "#5b8def"; const FILL_COLOR = "rgba(91, 141, 239, 0.28)"; const STROKE_COLOR = "rgba(91, 141, 239, 0.85)"; const GRID_COLOR = "rgba(255,255,255,0.06)"; const SPOKE_COLOR = "rgba(255,255,255,0.08)"; const DOT_COLOR = "#5b8def"; const CHART_TITLE = "Theoretical AI capability by occupational category"; const WATERMARK_TEXT = "johnmu.com"; const TITLE_H = 52; const WATERMARK_H = 36; function polarToXY(cx, cy, radius, angleDeg) { const rad = ((angleDeg - 90) * Math.PI) / 180; return { x: cx + radius * Math.cos(rad), y: cy + radius * Math.sin(rad) }; } function labelAnchor(angle) { const n = ((angle % 360) + 360) % 360; if (n > 10 && n < 170) return "start"; if (n > 190 && n < 350) return "end"; return "middle"; } function labelDy(angle) { const n = ((angle % 360) + 360) % 360; if (n > 100 && n < 260) return "0.8em"; if (n < 10 || n > 350) return "-0.4em"; return "0.35em"; } function RadarChartSVG({ values, hovered, onHover, size }) { const totalH = size + TITLE_H + WATERMARK_H; const cx = size / 2; const cy = size / 2 + TITLE_H; const maxR = size * 0.34; const labelR = maxR + 28; const angleStep = 360 / N; const rings = [20, 40, 60, 80, 100]; const points = OCCUPATIONS.map((occ, i) => { const val = values[occ.key] || 0; return polarToXY(cx, cy, (val / 100) * maxR, i * angleStep); }); const pathD = points.map((p, i) => `${i === 0 ? "M" : "L"} ${p.x} ${p.y}`).join(" ") + " Z"; return ( ); } function buildExportSVGString(values) { const S = 900; const totalH = S + TITLE_H + WATERMARK_H; const cx = S / 2; const cy = S / 2 + TITLE_H; const maxR = S * 0.34; const labelR = maxR + 28; const angleStep = 360 / N; const rings = [20, 40, 60, 80, 100]; const esc = (s) => s.replace(/&/g, "&").replace(//g, ">"); const p = []; p.push(``); return { svg: p.join("\n"), width: S * 2, height: totalH * 2 }; } function SliderRow({ occ, value, onChange, isHovered, onHover }) { return (
Share of job tasks that LLMs could theoretically perform. Adjust sliders, then share the URL or download as PNG.