// app.jsx — Ken Kelly portfolio prototype // One long page. Three visual directions. const { useState, useEffect, useRef, useCallback, useMemo } = React; // ───────────────────────────────────────────────────────────── content ── const BIO = { name: "Ken Kelly", handle: "kkelly", title: "Principal Software Architect", location: "South Florida, US", yearsExp: 20, available: true, blurb: "I build production frontends and backends that don't fall over. React, TypeScript, Go — 20+ years of shipping software that real customers depend on.", links: { email: "ken@kkelly.dev", github: "https://github.com/kenhkelly", linkedin: "https://www.linkedin.com/in/kenhkelly/", resume: "/resume.pdf", }, }; const NOW = [ { k: "building", v: "Replatforming Total Wine's web checkout — React + Go services." }, { k: "available", v: "Taking on 1–2 consulting engagements for Q3. Backend, frontend, or both." }, { k: "learning", v: "Deepening DevOps chops — Kubernetes, Terraform, and CI/CD pipeline design." }, { k: "location", v: "South Florida · ET (UTC−5/−4)" }, ]; const EXPERIENCE = [ { range: "2018 — present", company: "Total Wine & More", role: "Principal Software Architect", notes: "Architect the consumer web + native apps. Lead frontend platform, drive Go service migrations, mentor a team of 12.", stack: ["React", "React Native", "TypeScript", "Go", "GraphQL", "GCP", "Restate", "Redpanda"], }, { range: "2014 — 2018", company: "Senior Engineer", role: "E-commerce & SaaS clients", notes: "Full-stack lead on commerce, fulfillment, and CMS rebuilds. Took several products from MVP through scale.", stack: ["Node.js", "React", "Postgres", "Redis", "Docker"], }, { range: "2008 — 2014", company: "Independent / agency", role: "Frontend & full-stack", notes: "Client work across hospitality, retail, media. Built and ran a small agency for four of those years.", stack: ["PHP", "MySQL", "jQuery", "Backbone", "Rails"], }, { range: "2005 — 2008", company: "First gigs", role: "Web developer", notes: "Got my hands dirty. Tables-for-layout, Flash, PSD-to-HTML, the works.", stack: ["HTML", "CSS", "JS", "PHP"], }, ]; const PROJECTS = [ { id: "tw-mobile", title: "Total Wine & More — Mobile App", year: "2019 — present", role: "Tech Lead", summary: "Native iOS & Android storefront. Catalog browse, reorder, in-store pickup, wallet. 4.9★ on iOS with millions of downloads.", stack: ["React Native", "Swift", "Kotlin", "GraphQL", "Go"], metrics: [ { v: "4.9★", l: "App Store rating" }, { v: "8M+", l: "downloads" }, { v: "60Hz", l: "scroll on a 5-year-old phone" }, ], href: "https://apps.apple.com/us/app/total-wine-more/id1277318070", }, { id: "tw-web", title: "Total Wine & More — Web", year: "2018 — present", role: "Principal Engineer", summary: "Top-50 US e-commerce site by traffic. Lead frontend architecture, performance, A/B platform, design-system rollout.", stack: ["React", "TypeScript", "Next.js", "Go", "GraphQL", "Akamai"], metrics: [ { v: "92", l: "Lighthouse perf" }, { v: "<1.2s", l: "median LCP" }, { v: "1.5B", l: "annual GMV" }, ], href: "https://www.totalwine.com", }, ]; const SKILLS = { Languages: ["TypeScript", "JavaScript", "Go", "Swift", "Kotlin", "SQL"], Frontend: ["React", "React Native", "Next.js", "Vite", "CSS Architecture"], Backend: ["Go", "Node.js", "GraphQL", "REST", "Postgres", "Redis", "Restate", "Redpanda"], Platform: ["AWS", "GCP", "Docker", "Kubernetes", "Terraform", "CI/CD"], "Practice": ["System design", "Mentoring", "Tech strategy", "Code review"], }; // ───────────────────────────────────────────────────────────── tweaks ── const TWEAK_DEFAULTS = { direction: "terminal", accent: "#7CFFB2", density: "cozy", font: "jetbrains", }; const FONT_STACKS = { jetbrains: '"JetBrains Mono", ui-monospace, "Cascadia Code", Menlo, monospace', plex: '"IBM Plex Mono", ui-monospace, Menlo, monospace', geist: '"Geist Mono", "JetBrains Mono", ui-monospace, monospace', }; const DIRECTIONS = { terminal: { label: "Terminal", bg: "#06100B", bgAlt: "#0A1812", surface: "#0E1A14", border: "rgba(124,255,178,0.14)", text: "#C8E6D3", muted: "#5E7E6A", accent: "#7CFFB2", scanlines: true, promptChar: "$", }, console: { label: "Console", bg: "#0B0E14", bgAlt: "#10141C", surface: "#141923", border: "rgba(127,215,255,0.12)", text: "#D8E0EE", muted: "#6E7A91", accent: "#7FD7FF", scanlines: false, promptChar: "›", }, brutalist: { label: "Brutalist", bg: "#000000", bgAlt: "#0A0A0A", surface: "#0F0F0F", border: "rgba(255,180,84,0.18)", text: "#F2F2F2", muted: "#7A7A7A", accent: "#FFB454", scanlines: false, promptChar: "▌", }, }; // ───────────────────────────────────────────────────────────── helpers ── function useTime() { const [t, setT] = useState(() => new Date()); useEffect(() => { const id = setInterval(() => setT(new Date()), 1000); return () => clearInterval(id); }, []); return t; } function fmtClock(d) { return d.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit", second: "2-digit", hour12: false, }); } // ───────────────────────────────────────────────────────── terminal hero ── function TerminalHero({ theme }) { const lines = useMemo(() => ([ { type: "cmd", text: "whoami" }, { type: "out", text: "ken kelly · principal software engineer · south florida" }, { type: "cmd", text: "cat ./about.txt" }, { type: "out", text: BIO.blurb }, { type: "cmd", text: "ls ~/work | head -3" }, { type: "out", text: "total-wine-mobile/ total-wine-web/ go-weather/" }, { type: "cmd", text: "echo $STATUS" }, { type: "out", text: "available_for_consulting=true" }, ]), []); const [visible, setVisible] = useState([]); const [typing, setTyping] = useState(""); const [idx, setIdx] = useState(0); const [skipped, setSkipped] = useState(false); useEffect(() => { if (skipped) { setVisible(lines); return; } if (idx >= lines.length) return; const cur = lines[idx]; if (cur.type === "out") { const id = setTimeout(() => { setVisible(v => [...v, cur]); setIdx(i => i + 1); }, 180); return () => clearTimeout(id); } let i = 0; setTyping(""); const id = setInterval(() => { i++; setTyping(cur.text.slice(0, i)); if (i >= cur.text.length) { clearInterval(id); setTimeout(() => { setVisible(v => [...v, cur]); setTyping(""); setIdx(p => p + 1); }, 120); } }, 28); return () => clearInterval(id); }, [idx, skipped, lines]); const skip = () => setSkipped(true); return (
ken@kkelly.dev: ~
{visible.map((ln, i) => ln.type === "cmd" ? (
{theme.promptChar} {ln.text}
) : (
{ln.text}
) )} {!skipped && idx < lines.length && lines[idx].type === "cmd" && (
{theme.promptChar} {typing}
)} {(skipped || idx >= lines.length) && (
{theme.promptChar}
)}
); } // ──────────────────────────────────────────────────────────── cmd-k ── function CmdPalette({ open, onClose, sections }) { const [q, setQ] = useState(""); const [sel, setSel] = useState(0); const inputRef = useRef(null); const scrollToId = (id) => { const el = document.getElementById(id); if (!el) return; const y = el.getBoundingClientRect().top + window.scrollY - 70; window.scrollTo({ top: y, behavior: "smooth" }); }; const items = useMemo(() => { const list = [ ...sections.map(s => ({ kind: "Section", label: s.label, action: () => scrollToId(s.id) })), { kind: "Action", label: "Email Ken", action: () => { window.location.href = `mailto:${BIO.links.email}`; }}, { kind: "Action", label: "Open GitHub", action: () => { window.open(BIO.links.github, "_blank"); }}, { kind: "Action", label: "Open LinkedIn", action: () => { window.open(BIO.links.linkedin, "_blank"); }}, { kind: "Action", label: "Copy email address", action: () => { navigator.clipboard?.writeText(BIO.links.email); }}, { kind: "Action", label: "Download résumé", action: () => { alert("Résumé download would start here."); }}, ]; if (!q.trim()) return list; const needle = q.toLowerCase(); return list.filter(it => it.label.toLowerCase().includes(needle)); }, [q, sections]); useEffect(() => { if (open) { setQ(""); setSel(0); setTimeout(() => inputRef.current?.focus(), 30); } }, [open]); useEffect(() => { setSel(0); }, [q]); const onKey = (e) => { if (e.key === "Escape") { onClose(); } else if (e.key === "ArrowDown") { e.preventDefault(); setSel(s => Math.min(items.length - 1, s + 1)); } else if (e.key === "ArrowUp") { e.preventDefault(); setSel(s => Math.max(0, s - 1)); } else if (e.key === "Enter") { e.preventDefault(); items[sel]?.action(); onClose(); } }; if (!open) return null; return (
e.stopPropagation()}>
⌘K setQ(e.target.value)} onKeyDown={onKey} /> esc
{items.length === 0 && (
No matches.
)} {items.map((it, i) => (
setSel(i)} onClick={() => { it.action(); onClose(); }} > {it.kind} {it.label} {i === sel && }
))}
); } // ──────────────────────────────────────────────────────────── sections ── function Section({ id, label, num, children }) { return (
{num} {label}
{children}
); } function Hero({ theme, now }) { return (
~/kkelly.dev

Ken{" "} Kelly

{BIO.title} {BIO.yearsExp}+ years {BIO.location}

{BIO.blurb}

Hire for consulting press K anywhere
); } function AboutSection() { return (

I'm Ken. I write production software for a living and have been doing it since the early 2000s. These days I split my time between principal-level work at Total Wine & a small consulting practice on the side.

I'm equally at home in a React codebase and a Go service, which means I tend to get pulled into the gnarly seams between the two — performance, type-safety across the wire, dev-experience, build systems, and the boring infra that decides whether a product can actually scale.

I care about shipping, leaving codebases healthier than I found them, and mentoring engineers who'll outgrow me. I'm currently picking up 1–2 consulting clients for Q3 — happy to talk if you're stuck on something hard.

{Object.entries(SKILLS).map(([k, vs]) => (
{k.toLowerCase()}
{vs.map(v => {v})}
))}
); } function NowSection() { return (
{NOW.map(n => (
$ {n.k}
{n.v}
))}
); } function ExperienceSection() { return (
    {EXPERIENCE.map((e, i) => (
  1. {e.range}
    {e.role} · {e.company}
    {e.notes}
    {e.stack.map(s => {s})}
  2. ))}
); } function ProjectCard({ p }) { return (
id: {p.id}

{p.title}

{p.year}·{p.role}

{p.summary}

{p.metrics.map(m => (
{m.v}
{m.l}
))}
{p.stack.map(s => {s})}
visit ↗
); } function ProjectsSection() { return (
hover any card →
{PROJECTS.map(p => )}
); } function ContactSection() { const [copied, setCopied] = useState(false); const copy = () => { navigator.clipboard?.writeText(BIO.links.email); setCopied(true); setTimeout(() => setCopied(false), 1400); }; return (
{`$ cat > /var/mail/ken <
        
{BIO.links.email} github ↗ linkedin ↗
Best for: consulting engagements, technical advisory, hands-on architecture work.
); } // ──────────────────────────────────────────────────────────── chrome ── function TopBar({ onCmdK }) { const t = useTime(); return (
kkelly.dev / ~ /portfolio
available for consulting {fmtClock(t)} ET
); } function Footer() { return ( ); } // ──────────────────────────────────────────────────────────── root ── function App() { const t = TWEAK_DEFAULTS; const dir = DIRECTIONS[t.direction] || DIRECTIONS.terminal; const [paletteOpen, setPaletteOpen] = useState(false); // sections registry for cmd-k + j/k nav const sections = useMemo(() => ([ { id: "about", label: "01 · about" }, { id: "now", label: "02 · now" }, { id: "experience", label: "03 · experience" }, { id: "projects", label: "04 · projects" }, { id: "contact", label: "05 · contact" }, ]), []); // global keymap: cmd-k, j/k nav, g+h home useEffect(() => { const onKey = (e) => { const target = e.target; const isTyping = target && (target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable); if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") { e.preventDefault(); setPaletteOpen(o => !o); return; } if (isTyping) return; if (e.key === "j" || e.key === "k") { e.preventDefault(); const dirSign = e.key === "j" ? 1 : -1; const ids = ["top", ...sections.map(s => s.id)]; const tops = ids.map(id => { const el = document.getElementById(id); return el ? el.getBoundingClientRect().top + window.scrollY : Infinity; }); const curY = window.scrollY + 80; // current section = highest one whose top <= curY let curIdx = 0; for (let i = 0; i < tops.length; i++) if (tops[i] <= curY) curIdx = i; const nextIdx = Math.max(0, Math.min(ids.length - 1, curIdx + dirSign)); const el = document.getElementById(ids[nextIdx]); if (el) { const y = el.getBoundingClientRect().top + window.scrollY - 70; window.scrollTo({ top: y, behavior: "smooth" }); } } }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [sections]); // apply theme vars const styleVars = { "--bg": dir.bg, "--bg-alt": dir.bgAlt, "--surface": dir.surface, "--border": dir.border, "--text": dir.text, "--muted": dir.muted, "--accent": t.accent || dir.accent, "--font": FONT_STACKS[t.font] || FONT_STACKS.jetbrains, "--pad": t.density === "compact" ? "10px" : "16px", "--gap": t.density === "compact" ? "14px" : "22px", "--sect-y": t.density === "compact" ? "64px" : "108px", "--hero-y": t.density === "compact" ? "72px" : "128px", }; return (
setPaletteOpen(true)} />
); } ReactDOM.createRoot(document.getElementById("root")).render();