Snapshot: full project state

This commit is contained in:
2026-10-06 23:43:39 -07:00
commit 0ec1dedf31
12 changed files with 1250 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Indiana Holmes — Self-Hosted AI & Homelab Infrastructure</title>
<meta name="description" content="I get local AI running on hardware you own — GPU passthrough, multi-host Ollama routing, and self-hosted LLMs that never leave your network.">
<style>
:root{
--bg:#0a0e14; --bg2:#0f1520; --panel:#121a26; --line:#1e2a3a;
--text:#d7e0ea; --muted:#7f8ea3; --accent:#4ade80; --accent2:#38bdf8;
--amber:#fbbf24; --mono:'SFMono-Regular',ui-monospace,'JetBrains Mono',Consolas,monospace;
--sans:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg);color:var(--text);font-family:var(--sans);line-height:1.6;
-webkit-font-smoothing:antialiased;}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
.wrap{max-width:860px;margin:0 auto;padding:0 24px}
.mono{font-family:var(--mono)}
.accent{color:var(--accent)}
/* nav */
nav{display:flex;justify-content:space-between;align-items:center;padding:22px 0;border-bottom:1px solid var(--line)}
.logo{font-family:var(--mono);font-weight:700;font-size:15px;letter-spacing:.5px}
.logo .prompt{color:var(--accent)}
.logo .cursor{color:var(--accent);animation:blink 1s step-end infinite}
@keyframes blink{50%{opacity:0}}
nav .links a{color:var(--muted);margin-left:22px;font-size:14px}
nav .links a:hover{color:var(--text)}
/* hero */
.hero{padding:72px 0 48px}
.hero .tag{display:inline-block;font-family:var(--mono);font-size:12px;color:var(--accent);
border:1px solid var(--line);background:var(--bg2);padding:4px 12px;border-radius:20px;margin-bottom:22px;letter-spacing:.5px}
h1{font-size:44px;line-height:1.15;font-weight:800;letter-spacing:-.5px;margin-bottom:20px}
h1 .hl{color:var(--accent)}
.lede{font-size:19px;color:var(--muted);max-width:640px;margin-bottom:28px}
.cta{display:flex;gap:14px;flex-wrap:wrap}
.btn{display:inline-block;padding:13px 24px;border-radius:8px;font-weight:600;font-size:15px;border:1px solid transparent}
.btn.primary{background:var(--accent);color:#04140a}
.btn.primary:hover{background:#5ee89a;text-decoration:none}
.btn.ghost{border-color:var(--line);color:var(--text)}
.btn.ghost:hover{border-color:var(--accent);text-decoration:none}
/* stats */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);
border:1px solid var(--line);border-radius:12px;overflow:hidden;margin:8px 0 64px}
.stat{background:var(--panel);padding:22px;text-align:center}
.stat .n{font-family:var(--mono);font-size:28px;font-weight:700;color:var(--accent)}
.stat .l{font-size:12.5px;color:var(--muted);margin-top:4px}
/* sections */
section{padding:40px 0}
.sec-head{font-family:var(--mono);font-size:13px;color:var(--accent2);letter-spacing:1px;
text-transform:uppercase;margin-bottom:24px}
.sec-head::before{content:"▸ ";color:var(--accent)}
h2{font-size:28px;font-weight:800;letter-spacing:-.3px;margin-bottom:14px}
.sub{color:var(--muted);font-size:16px;margin-bottom:32px;max-width:640px}
/* projects */
.project{background:var(--panel);border:1px solid var(--line);border-radius:12px;
padding:30px;margin-bottom:22px}
.project h3{font-size:21px;font-weight:700;margin-bottom:6px}
.project .meta{font-family:var(--mono);font-size:12px;color:var(--muted);margin-bottom:18px}
.project .grid{display:grid;grid-template-columns:1fr;gap:18px}
.prow{display:grid;grid-template-columns:120px 1fr;gap:16px}
.prow .k{font-family:var(--mono);font-size:13px;color:var(--amber);font-weight:600;text-transform:uppercase;letter-spacing:.5px}
.prow .v{font-size:15px;color:var(--text)}
.tools{margin-top:18px;padding-top:16px;border-top:1px solid var(--line)}
.tools span{display:inline-block;font-family:var(--mono);font-size:12px;color:var(--accent2);
background:var(--bg2);border:1px solid var(--line);border-radius:6px;padding:3px 10px;margin:0 6px 6px 0}
/* services */
.svc{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.svc-item{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:24px}
.svc-item h4{font-size:16px;font-weight:700;margin-bottom:6px}
.svc-item .rate{font-family:var(--mono);color:var(--accent);font-size:15px;font-weight:600}
.svc-item p{font-size:14px;color:var(--muted);margin-top:8px}
/* contact */
.contact{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:36px;text-align:center;margin-bottom:40px}
.contact h2{margin-bottom:10px}
.contact p{color:var(--muted);margin-bottom:22px}
.contact .email{font-family:var(--mono);font-size:17px;color:var(--accent)}
footer{border-top:1px solid var(--line);padding:28px 0 40px;text-align:center;color:var(--muted);font-size:13px}
footer a{color:var(--muted)}
@media(max-width:680px){
h1{font-size:32px}
.stats{grid-template-columns:repeat(2,1fr)}
.prow{grid-template-columns:1fr}
.svc{grid-template-columns:1fr}
nav .links a{display:none}
}
</style>
</head>
<body>
<div class="wrap">
<nav>
<div class="logo"><span class="prompt">~</span> ih<span class="cursor">▊</span></div>
<div class="links">
<a href="#work">work</a>
<a href="#services">services</a>
<a href="#contact">contact</a>
</div>
</nav>
<header class="hero">
<span class="tag">self-hosted AI · homelab · hardware</span>
<h1>I get local AI running on<br>hardware <span class="hl">you own</span>.</h1>
<p class="lede">GPU passthrough, multi-host Ollama routing, and self-hosted LLMs that never
leave your network. If your GPU won't cooperate with Ollama, I can fix it.</p>
<div class="cta">
<a class="btn primary" href="#contact">Hire me</a>
<a class="btn ghost" href="#work">See the work</a>
</div>
</header>
<div class="stats">
<div class="stat"><div class="n">4</div><div class="l">GPU lanes routed</div></div>
<div class="stat"><div class="n">100K</div><div class="l">ctx on 16GB VRAM</div></div>
<div class="stat"><div class="n">13.2</div><div class="l">tok/s on a $100 GPU</div></div>
<div class="stat"><div class="n">3</div><div class="l">hosts, one model std</div></div>
</div>
<section id="work">
<div class="sec-head">01 · Selected work</div>
<h2>Proof, not promises.</h2>
<p class="sub">Real builds from real hardware. Each one solves the exact problem people
pay to have solved.</p>
<div class="project">
<h3>R630 → Always-On Ollama Inference (GPU Passthrough)</h3>
<div class="meta">Dell R630 · Quadro M4000 · Vulkan fallback · 13.2 tok/s</div>
<div class="prow"><div class="k">Problem</div><div class="v">A retired R630 needed to become a 24/7 local LLM box for a fleet of apps — instead of each app spinning up its own Ollama or renting cloud GPU time.</div></div>
<div class="prow"><div class="k">Approach</div><div class="v">Docker + nvidia-toolkit, Ollama as a systemd service (LAN-open, keep_alive, model pinning). Diagnosed the undocumented gotcha: Ollama 0.34 dropped CUDA for Maxwell, so it silently fell back to Vulkan — benchmarked it properly instead of declaring it dead.</div></div>
<div class="prow"><div class="k">Result</div><div class="v">ornith-1.5:9b at 100% GPU, 13.2 tok/s on a $100 retired card — the always-on consolidation lane every server app now points at.</div></div>
<div class="tools"><span>Proxmox</span><span>Docker</span><span>Ollama</span><span>Vulkan</span><span>ZFS</span><span>systemd</span><span>iDRAC</span></div>
</div>
<div class="project">
<h3>4-Lane Multi-GPU LLM Routing Architecture</h3>
<div class="meta">RTX 4080 SUPER · RTX 3070 · M4000 · MacBook · one model standard</div>
<div class="prow"><div class="k">Problem</div><div class="v">Three GPUs + a MacBook were being used ad hoc — every app guessed where to send its LLM call, causing GPU saturation, cold-model timeouts, and latency-critical jobs queued behind batch work.</div></div>
<div class="prow"><div class="k">Approach</div><div class="v">Four explicit lanes (premium / batch / always-on / voice) with a single model standard and per-lane latency/VRAM routing. Shared one GPU between Ollama and ComfyUI via HyperSwap.</div></div>
<div class="prow"><div class="k">Result</div><div class="v">100K-token context on 16GB VRAM with zero CPU offload; prefill pushed 308 → 1867 tok/s. Every consumer mapped to the lane that fits its class.</div></div>
<div class="tools"><span>Ollama multi-host</span><span>CUDA</span><span>Vulkan</span><span>Flash Attention</span><span>KV-cache quant</span><span>HyperSwap</span><span>ComfyUI</span></div>
</div>
<div class="project">
<h3>Android TV Box Rooting + Emulation (SK4 Pro)</h3>
<div class="meta">UGOOS SK4 Pro · Amlogic · Android 14 · Magisk · NetherSX2</div>
<div class="prow"><div class="k">Problem</div><div class="v">Turn an Android TV box into a retro-emulation console (N64/PS1/PS2) — which required root, BIOS/ROM staging, and core config, all below the app layer.</div></div>
<div class="prow"><div class="k">Approach</div><div class="v">Pushed Magisk 30.7, patched the A/B boot image, staged PS1/PS2 BIOS + ROMs, configured RetroArch cores, and managed it over ADB + SMB.</div></div>
<div class="prow"><div class="k">Result</div><div class="v">A rooted, emulation-ready TV box with clean ROM/BIOS layout, side-loaded Jellyfin, managed fully remote over the LAN.</div></div>
<div class="tools"><span>Amlogic A/B</span><span>Magisk</span><span>ADB</span><span>RetroArch</span><span>NetherSX2</span><span>Samba</span><span>ESP32-S3</span></div>
</div>
</section>
<section id="services">
<div class="sec-head">02 · What I do</div>
<h2>Services & rates.</h2>
<div class="svc">
<div class="svc-item"><h4>Self-hosted AI / GPU passthrough</h4><div class="rate">$75/hr</div><p>Local LLM on your own hardware — GPU passthrough, Ollama setup, multi-host routing, context/VRAM optimization.</p></div>
<div class="svc-item"><h4>Homelab & sysadmin</h4><div class="rate">$65/hr</div><p>Proxmox, Docker, ZFS, backups (PBS), networking. Turn a pile of servers into one clean infrastructure.</p></div>
<div class="svc-item"><h4>Hardware / embedded</h4><div class="rate">$65/hr</div><p>Android TV rooting, ESP32 firmware, ADB automation, boot-image patching — the below-the-OS-layer stuff.</p></div>
<div class="svc-item"><h4>Defensive security review</h4><div class="rate">$95/hr</div><p>Authorized vulnerability assessment and app-security review. Scoped, documented, lawful.</p></div>
</div>
</section>
<section id="contact">
<div class="sec-head">03 · Contact</div>
<div class="contact">
<h2>Have a GPU that won't cooperate?</h2>
<p>Tell me your hardware and what's stuck. I'll tell you if it's a 2-command fix or a real job.</p>
<div class="email">indianaholmes1@icloud.com</div>
<div style="margin-top:18px">
<a class="btn primary" href="mailto:indianaholmes1@icloud.com?subject=Local%20LLM%20setup">Email me</a>
</div>
</div>
</section>
<footer>
<p>Indiana Holmes · Self-Hosted AI & Homelab Infrastructure</p>
<p style="margin-top:8px">
<a href="https://buymeacoffee.com/r26xrthzttg" target="_blank" rel="noopener">☕ Support my work</a>
&nbsp;·&nbsp; <span class="mono">upwork · reddit · gumroad</span>
</p>
</footer>
</div>
</body>
</html>

598
portfolio-site/index.html Normal file
View File

@@ -0,0 +1,598 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Indiana Holmes — Generalist Engineer & Self-Hosted Builder</title>
<meta name="description" content="A self-taught generalist who builds and runs his own servers, AI, firmware, and payments. Everything here is live.">
<style>
:root{
--bg:#04060d; --panel:rgba(14,18,32,.52); --panel2:rgba(20,26,46,.62);
--line:rgba(120,160,255,.13); --text:#e7ecff; --muted:#8b97b6;
--cyan:#67e8f9; --violet:#a78bfa; --green:#4ade80; --amber:#fbbf24; --ember:#ff6b3d;
--mono:'SFMono-Regular',ui-monospace,'JetBrains Mono',Consolas,monospace;
--sans:-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
body{
background:var(--bg);color:var(--text);font-family:var(--sans);line-height:1.65;
-webkit-font-smoothing:antialiased;overflow-x:hidden;
}
/* live physics background */
#cosmos{position:fixed;inset:0;z-index:-1;display:block}
a{color:var(--cyan);text-decoration:none;transition:.2s}
a:hover{text-shadow:0 0 18px rgba(103,232,249,.55)}
.wrap{max-width:1040px;margin:0 auto;padding:0 30px}
.mono{font-family:var(--mono)}
.reveal{opacity:0;transform:translateY(26px);transition:opacity .8s ease,transform .8s ease}
.reveal.in{opacity:1;transform:none}
/* nav */
nav{position:sticky;top:0;z-index:10;display:flex;justify-content:space-between;align-items:center;
padding:18px 0;backdrop-filter:blur(14px);
background:linear-gradient(180deg,rgba(4,6,13,.82),rgba(4,6,13,.35));}
.logo{font-family:var(--mono);font-weight:700;font-size:15px;letter-spacing:.5px}
.logo .prompt{color:var(--green)}
.logo .cursor{color:var(--green);animation:blink 1s step-end infinite}
@keyframes blink{50%{opacity:0}}
nav .links a{color:var(--muted);margin-left:22px;font-size:14px}
nav .links a:hover{color:var(--text);text-shadow:none}
/* hero */
.hero{padding:110px 0 40px;text-align:left;min-height:72vh;display:flex;flex-direction:column;justify-content:center}
.badge{display:inline-block;font-family:var(--mono);font-size:12px;color:var(--cyan);
border:1px solid var(--line);background:var(--panel);padding:5px 14px;border-radius:20px;
margin-bottom:26px;letter-spacing:1px;backdrop-filter:blur(8px);width:fit-content}
h1{font-size:56px;line-height:1.08;font-weight:800;letter-spacing:-.8px;margin-bottom:24px;max-width:760px}
h1 .hl{background:linear-gradient(92deg,var(--ember),var(--amber),var(--cyan));
-webkit-background-clip:text;background-clip:text;color:transparent}
.term{font-family:var(--mono);font-size:16px;color:var(--green);min-height:1.6em;margin-bottom:22px}
.term .dim{color:var(--muted)}
.lede{font-size:19px;color:var(--muted);max-width:660px;margin-bottom:32px}
.lede b{color:var(--text);font-weight:600}
.cta{display:flex;gap:14px;flex-wrap:wrap}
.btn{display:inline-block;padding:14px 28px;border-radius:10px;font-weight:600;font-size:15px;
border:1px solid transparent;transition:.25s;cursor:pointer}
.btn.primary{background:linear-gradient(90deg,var(--cyan),var(--violet));color:#04060d}
.btn.primary:hover{box-shadow:0 0 28px rgba(103,232,249,.45);transform:translateY(-2px);text-shadow:none}
.btn.ghost{border-color:var(--line);color:var(--text);background:var(--panel);backdrop-filter:blur(8px)}
.btn.ghost:hover{border-color:var(--cyan);box-shadow:0 0 20px rgba(103,232,249,.2)}
/* stats */
.stats{display:grid;grid-template-columns:repeat(4,1fr);gap:1px;background:var(--line);
border:1px solid var(--line);border-radius:14px;overflow:hidden;margin:8px 0 76px;
backdrop-filter:blur(8px)}
.stat{background:var(--panel);padding:24px;text-align:center;transition:.3s}
.stat:hover{background:var(--panel2)}
.stat .n{font-family:var(--mono);font-size:28px;font-weight:700;
background:linear-gradient(90deg,var(--ember),var(--amber));
-webkit-background-clip:text;background-clip:text;color:transparent}
.stat .l{font-size:12.5px;color:var(--muted);margin-top:5px}
/* sections */
section{padding:46px 0}
.sec-head{font-family:var(--mono);font-size:13px;color:var(--violet);letter-spacing:2px;
text-transform:uppercase;margin-bottom:20px}
.sec-head::before{content:"▸ ";color:var(--cyan)}
h2{font-size:32px;font-weight:800;letter-spacing:-.3px;margin-bottom:12px}
.sub{color:var(--muted);font-size:16px;margin-bottom:34px;max-width:680px}
/* skills */
.skillgroup{margin-bottom:26px}
.skillgroup h4{font-family:var(--mono);font-size:12px;color:var(--amber);letter-spacing:1.5px;
text-transform:uppercase;margin-bottom:12px;font-weight:600}
.skills{display:flex;flex-wrap:wrap;gap:9px}
.skill{font-family:var(--mono);font-size:13px;color:var(--cyan);background:var(--panel);
border:1px solid var(--line);border-radius:8px;padding:7px 13px;transition:.25s;cursor:default}
.skill:hover{transform:translateY(-3px);border-color:var(--cyan);box-shadow:0 6px 20px rgba(103,232,249,.2)}
/* projects */
.grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.card{position:relative;background:var(--panel);border:1px solid var(--line);border-radius:16px;
padding:26px;backdrop-filter:blur(10px);overflow:hidden;transition:transform .3s ease,border-color .3s ease,box-shadow .3s ease;
display:flex;flex-direction:column;gap:12px}
.card::before{content:"";position:absolute;inset:0;border-radius:16px;pointer-events:none;
background:radial-gradient(500px 240px at var(--mx,50%) var(--my,0%),rgba(255,107,61,.14),transparent 60%);
opacity:0;transition:opacity .3s}
.card:hover::before{opacity:1}
.card:hover{transform:translateY(-4px);border-color:rgba(255,107,61,.45);box-shadow:0 18px 44px rgba(0,0,0,.55)}
.card h3{font-size:18px;font-weight:700;line-height:1.25}
.card h3 a{color:var(--text)}
.card h3 a:hover{color:var(--cyan);text-shadow:none}
.card .host{font-family:var(--mono);font-size:11px;color:var(--violet);letter-spacing:.2px}
.card .what{font-size:14px;color:var(--muted);flex:1}
.card .why{border-top:1px solid var(--line);padding-top:12px;font-size:13px;color:var(--amber)}
.card .why b{font-family:var(--mono);font-size:11px;color:var(--cyan);letter-spacing:1px;
text-transform:uppercase;display:block;margin-bottom:3px;font-weight:600}
/* timeline */
.tl{position:relative;margin:20px 0 8px;padding-left:28px}
.tl::before{content:"";position:absolute;left:8px;top:4px;bottom:4px;width:1px;
background:linear-gradient(180deg,var(--cyan),var(--violet),transparent)}
.tl-item{position:relative;margin-bottom:28px}
.tl-item::before{content:"";position:absolute;left:-26px;top:6px;width:11px;height:11px;border-radius:50%;
background:var(--bg);border:2px solid var(--cyan);box-shadow:0 0 12px rgba(103,232,249,.6)}
.tl-item .when{font-family:var(--mono);font-size:12px;color:var(--violet);letter-spacing:.5px}
.tl-item .what{font-weight:700;font-size:16px;margin:2px 0}
.tl-item .where{font-size:14px;color:var(--muted)}
/* services */
.svc{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.svc-item{background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:26px;
backdrop-filter:blur(8px);transition:.3s}
.svc-item:hover{transform:translateY(-4px);border-color:var(--violet);box-shadow:0 12px 30px rgba(167,139,250,.15)}
.svc-item h4{font-size:16px;font-weight:700;margin-bottom:4px}
.svc-item .rate{font-family:var(--mono);color:var(--green);font-size:16px;font-weight:600}
.svc-item p{font-size:13.5px;color:var(--muted);margin-top:8px}
/* contact */
.contact{background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:46px;
text-align:center;margin:40px 0 48px;backdrop-filter:blur(10px);position:relative;overflow:hidden}
.contact::before{content:"";position:absolute;inset:0;pointer-events:none;
background:radial-gradient(500px 200px at 50% 0%,rgba(255,107,61,.12),transparent 70%)}
.contact h2{margin-bottom:10px}
.contact p{color:var(--muted);margin-bottom:24px;position:relative}
.contact .email{font-family:var(--mono);font-size:18px;color:var(--cyan);position:relative}
.contact .cta{justify-content:center;position:relative;margin-top:20px}
footer{border-top:1px solid var(--line);padding:30px 0 46px;text-align:center;color:var(--muted);font-size:13px}
footer a{color:var(--muted)}
@media(max-width:860px){
.grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:680px){
h1{font-size:36px}
.stats{grid-template-columns:repeat(2,1fr)}
.grid{grid-template-columns:1fr}
.svc{grid-template-columns:1fr}
nav .links a{display:none}
.hero{min-height:auto;padding:80px 0 32px}
}
</style>
</head>
<body>
<canvas id="cosmos"></canvas>
<div class="wrap">
<nav>
<div class="logo"><span class="prompt">~</span> indiana.holmes<span class="cursor">▊</span></div>
<div class="links">
<a href="#skills">skills</a>
<a href="#work">built</a>
<a href="#services">services</a>
<a href="#contact">contact</a>
</div>
</nav>
<header class="hero">
<span class="badge reveal">generalist engineer · self-taught · runs his own lab</span>
<h1 class="reveal">I build things on computers — and run most of them <span class="hl">myself</span>.</h1>
<div class="term reveal"><span class="dim">$</span> <span id="typewriter"></span><span class="cursor">▊</span></div>
<p class="lede reveal">Firmware, servers, AI, payments, and the web — I've taught myself the whole stack by building it.
Everything below is <b>live and real</b>, not mockups: the actual services running in my lab right now.</p>
<div class="cta reveal">
<a class="btn primary" href="#contact">Get in touch</a>
<a class="btn ghost" href="#work">See what I run ↓</a>
</div>
</header>
<div class="stats reveal">
<div class="stat"><div class="n">69</div><div class="l">services running</div></div>
<div class="stat"><div class="n">3,685</div><div class="l">MCP servers indexed</div></div>
<div class="stat"><div class="n">31</div><div class="l">Bitcoin stores</div></div>
<div class="stat"><div class="n">8</div><div class="l">sites self-publishing</div></div>
</div>
<section id="skills" class="reveal">
<div class="sec-head">01 · Capabilities</div>
<h2>A broad toolbox.</h2>
<p class="sub">I'm a generalist — I move between the OS layer, the network, the models, and the metal. Here's what I actually reach for.</p>
<div class="skillgroup"><h4>Systems &amp; infrastructure</h4>
<div class="skills">
<span class="skill">Proxmox</span><span class="skill">Docker</span><span class="skill">ZFS · SLOG/L2ARC</span>
<span class="skill">Linux · systemd</span><span class="skill">nginx</span><span class="skill">Networking</span>
<span class="skill">Cloudflare Tunnels</span><span class="skill">Backups · PBS</span>
</div>
</div>
<div class="skillgroup"><h4>AI &amp; models</h4>
<div class="skills">
<span class="skill">Ollama · multi-host</span><span class="skill">GPU passthrough</span>
<span class="skill">Local LLMs</span><span class="skill">Flash Attention</span><span class="skill">KV-cache quant</span>
<span class="skill">MCP / agents</span><span class="skill">ComfyUI</span>
</div>
</div>
<div class="skillgroup"><h4>Software</h4>
<div class="skills">
<span class="skill">Python</span><span class="skill">JavaScript</span><span class="skill">Flask</span>
<span class="skill">React / Vite</span><span class="skill">SQL</span><span class="skill">REST APIs</span>
</div>
</div>
<div class="skillgroup"><h4>Hardware &amp; embedded</h4>
<div class="skills">
<span class="skill">ESP32 · firmware</span><span class="skill">ADB / Android</span><span class="skill">Magisk</span>
<span class="skill">Amlogic A/B</span><span class="skill">Boot images</span><span class="skill">RetroArch</span>
</div>
</div>
<div class="skillgroup"><h4>Payments &amp; security</h4>
<div class="skills">
<span class="skill">Bitcoin · Lightning</span><span class="skill">BTCPay</span><span class="skill">Self-hosted payments</span>
<span class="skill">Defensive security</span><span class="skill">OSINT</span>
</div>
</div>
</section>
<section id="work" class="reveal">
<div class="sec-head">02 · Built &amp; running</div>
<h2>Things I've built — and still run.</h2>
<p class="sub">Each one is linked and live. I didn't build these for a resume; I built them because I wanted them, and they're up 24/7.</p>
<div class="grid">
<div class="card" data-tilt>
<h3><a href="https://mcp.thetempleofdoom.com" target="_blank" rel="noopener">Omninexus</a></h3>
<div class="host">mcp.thetempleofdoom.com</div>
<div class="what">An MCP hub that indexes 3,685 AI servers — discovery, search, and health checks in one place.</div>
<div class="why"><b>why it matters</b> Agents discover any capability instead of hard-coding integrations. One endpoint for thousands of tools.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://hyperion.thetempleofdoom.com" target="_blank" rel="noopener">Hyperion</a></h3>
<div class="host">hyperion.thetempleofdoom.com</div>
<div class="what">An app store for AI agents — publish, discover, and call MCP tools, paid over Bitcoin.</div>
<div class="why"><b>why it matters</b> Machine-to-machine billing: an agent pays for a tool the same way you'd buy an API key.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://argus.thetempleofdoom.com" target="_blank" rel="noopener">ARGUS</a></h3>
<div class="host">argus.thetempleofdoom.com</div>
<div class="what">Rent-a-red-teamer — web-vuln scanning and OSINT for autonomous agents, running on Kali.</div>
<div class="why"><b>why it matters</b> Turns a red-team engagement into a metered API call instead of a manual project.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://astraea.thetempleofdoom.com" target="_blank" rel="noopener">Astraea</a></h3>
<div class="host">astraea.thetempleofdoom.com</div>
<div class="what">A Washington divorce-law assistant with RAG over verified statute and DV-safety guardrails.</div>
<div class="why"><b>why it matters</b> Answers grounded in real law — not a model hallucinating case law from memory.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://thetempleofdoom.com" target="_blank" rel="noopener">The Temple</a></h3>
<div class="host">thetempleofdoom.com</div>
<div class="what">A live index of all 69 self-hosted services, plus a provably-fair Bitcoin raffle.</div>
<div class="why"><b>why it matters</b> One honest dashboard for an entire fleet — every card is a live service, not a screenshot.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://tarot.thetempleofdoom.com" target="_blank" rel="noopener">Tarro</a></h3>
<div class="host">tarot.thetempleofdoom.com</div>
<div class="what">A tarot reader that quotes Waite and Wilhelm/Baynes instead of guessing.</div>
<div class="why"><b>why it matters</b> Knowledge apps that cite their sources — the model reads real texts, not vibes.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://nebula.thetempleofdoom.com" target="_blank" rel="noopener">Nebula</a></h3>
<div class="host">nebula.thetempleofdoom.com</div>
<div class="what">A paid image-generation GUI on a self-hosted ComfyUI stack.</div>
<div class="why"><b>why it matters</b> Consumer-grade UI on raw diffusion models — no cloud, your own GPU.</div>
</div>
<div class="card" data-tilt>
<h3><a href="https://ai.thetempleofdoom.com" target="_blank" rel="noopener">Publisher fleet</a></h3>
<div class="host">ai · tech · science · crypto · linux · gaming · diy · guides</div>
<div class="what">Eight authority sites that research, write, and self-publish — four posts a day each.</div>
<div class="why"><b>why it matters</b> A content engine that runs itself, end to end, with no one at the wheel.</div>
</div>
<div class="card" data-tilt>
<h3>Multi-GPU LLM routing</h3>
<div class="host">3 GPUs + a MacBook · internal</div>
<div class="what">Four GPU lanes and one model standard across three GPUs and a MacBook, routed by latency and VRAM.</div>
<div class="why"><b>why it matters</b> Any app gets the right model on the right lane — no saturation, no cold-model timeouts.</div>
</div>
</div>
<p class="sub" style="margin-top:30px">And more: <a href="https://evergreenapplicator.thetempleofdoom.com" target="_blank" rel="noopener">Evergreen Applicator</a> (WA pesticide exam prep),
<a href="https://signalsearcher.thetempleofdoom.com" target="_blank" rel="noopener">Signal Miner</a> (Telegram market intel),
<a href="https://rigel.thetempleofdoom.com" target="_blank" rel="noopener">Rigel</a> (no-KYC SOCKS5),
<a href="https://lynx.thetempleofdoom.com" target="_blank" rel="noopener">LYNX</a> (forensics API),
<a href="https://supernova.thetempleofdoom.com" target="_blank" rel="noopener">Supernova</a> (SMM) — the full list is at
<a href="https://thetempleofdoom.com" target="_blank" rel="noopener">thetempleofdoom.com</a>.</p>
</section>
<section id="experience" class="reveal">
<div class="sec-head">03 · Trajectory</div>
<h2>How I got here.</h2>
<p class="sub">Self-taught. I got into this by running my own servers and breaking them a lot.</p>
<div class="tl">
<div class="tl-item"><div class="when">2024 — now</div><div class="what">Independent engineer</div><div class="where">Built and run a homelab: a Proxmox fleet, GPU LLM routing, and a stack of self-hosted services and apps.</div></div>
<div class="tl-item"><div class="when">2023 — now</div><div class="what">Field operations &amp; logistics</div><div class="where">Lime — operations in the field; honed the "diagnose and fix under pressure" mindset.</div></div>
<div class="tl-item"><div class="when">2014 — 2023</div><div class="what">Master grower / controlled-environment agriculture</div><div class="where">Managed precision environments — the same systems thinking I apply to hardware.</div></div>
</div>
</section>
<section id="services" class="reveal">
<div class="sec-head">04 · Services &amp; rates</div>
<h2>What I can help with.</h2>
<div class="svc">
<div class="svc-item"><h4>Self-hosted AI / GPU passthrough</h4><div class="rate">$75/hr</div><p>Local LLM on your own hardware — GPU passthrough, Ollama setup, multi-host routing, context/VRAM optimization.</p></div>
<div class="svc-item"><h4>Homelab &amp; sysadmin</h4><div class="rate">$65/hr</div><p>Proxmox, Docker, ZFS, backups, networking. Turn a pile of servers into one clean infrastructure.</p></div>
<div class="svc-item"><h4>Hardware / embedded</h4><div class="rate">$65/hr</div><p>Android TV rooting, ESP32 firmware, ADB automation, boot-image patching — the below-the-OS-layer stuff.</p></div>
<div class="svc-item"><h4>Defensive security review</h4><div class="rate">$95/hr</div><p>Authorized vulnerability assessment and app-security review. Scoped, documented, lawful.</p></div>
</div>
</section>
<section id="contact" class="reveal">
<div class="sec-head">05 · Contact</div>
<div class="contact">
<h2>Building something similar? Stuck on a local LLM or GPU setup?</h2>
<p>Tell me what you're running and what's failing. Sometimes it's a two-command fix.</p>
<div class="email">indianaholmes1@icloud.com</div>
<div class="cta">
<a class="btn primary" href="mailto:indianaholmes1@icloud.com?subject=Project">Email me</a>
<a class="btn ghost" href="https://thetempleofdoom.com" target="_blank" rel="noopener">See the whole lab</a>
</div>
</div>
</section>
<footer>
<p>Indiana Holmes · Generalist Engineer · Self-Hosted Builder</p>
<p style="margin-top:8px">
<a href="https://buymeacoffee.com/r26xrthzttg" target="_blank" rel="noopener">☕ Support my work</a>
&nbsp;·&nbsp; <span class="mono">upwork · reddit · gumroad</span>
</p>
</footer>
</div>
<script>
/* ═══════════════════════════════════════════════════════════
BACKGROUND — a physics-bound black hole with a fire accretion
disk. Orbits are Keplerian (inner faster), particles spiral
inward, one side is doppler-bright, and both the cursor and
page scroll bend and move it. Self-contained, no libraries.
═══════════════════════════════════════════════════════════ */
const cv = document.getElementById('cosmos');
const ctx = cv.getContext('2d');
let W=0,H=0,DPR=1;
let stars=[], parts=[], jets=[], fog=[];
let bh = {x:0,y:0,R:0, px:0,py:0, tiltX:0, tiltY:0};
let scroll=0, mx=0.5, my=0.5, tmx=0.5, tmy=0.5;
function resize(){
DPR = Math.min(window.devicePixelRatio||1, 2);
W = cv.width = Math.floor(innerWidth * DPR);
H = cv.height = Math.floor(innerHeight * DPR);
cv.style.width = innerWidth+'px';
cv.style.height = innerHeight+'px';
makeStars();
makeFog();
initBH();
}
function makeStars(){
stars=[];
const n=Math.min(560, Math.max(200, Math.floor(innerWidth*innerHeight/1500)));
for(let i=0;i<n;i++){
const tint = Math.random();
const c = tint<0.72 ? '210,220,255' : (tint<0.88 ? '255,214,180' : '165,200,255');
stars.push({x:Math.random()*W, y:Math.random()*H,
r:(Math.random()*1.3+.3)*DPR, a:Math.random()*.6+.15, tw:Math.random()*6.28,
sp:Math.random()*.3+.05, c});
}
}
function makeFog(){
fog=[];
const n=7;
for(let i=0;i<n;i++){
fog.push({
x:Math.random()*W, y:Math.random()*H,
r:(Math.random()*0.35+0.25)*Math.max(W,H),
hue:Math.random()<0.5 ? 'rgba(120,140,220,' : (Math.random()<0.5 ? 'rgba(160,110,220,' : 'rgba(200,90,60,'),
a:0.02+Math.random()*0.025,
dx:(Math.random()-.5)*0.06, dy:(Math.random()-.5)*0.04
});
}
}
function initBH(){
bh.R = Math.min(W,H)*0.155;
bh.x = W*0.5; bh.y = H*0.40;
bh.px = bh.x; bh.py = bh.y;
const N = Math.floor(Math.min(2200, Math.max(1100, innerWidth*innerHeight/280)));
parts=[];
for(let i=0;i<N;i++){
parts.push({
a: Math.random()*6.2832,
r: bh.R*(1.15 + Math.pow(Math.random(),1.6)*1.3),
k: 0.75 + Math.random()*0.9, // Keplerian speed factor
s: (0.5 + Math.random()*1.8)*DPR,
o: 0.35 + Math.random()*0.65, // base opacity
fl: Math.random()*6.28, // flicker phase
fs: 0.5 + Math.random()*1.5 // flicker speed
});
}
jets=[];
for(let i=0;i<90;i++) jets.push({d:(Math.random()<.5?-1:1), t:Math.random()*6.28,
sp:0.5+Math.random()*1.2, len:(0.8+Math.random()*1.6), off:Math.random()*6.28});
}
// fire palette: deep red → orange → warm gold (never white-hot)
function fireColor(heat, o){
heat = Math.max(0, Math.min(1, heat));
let r,g,b;
if(heat < 0.5){ const t=heat/0.5; r=255; g=Math.floor(28+t*145); b=Math.floor(8+t*38); }
else { const t=(heat-0.5)/0.5; r=255; g=Math.floor(173+t*42); b=Math.floor(46+t*26); }
return `rgba(${r},${g},${b},${o})`;
}
function draw(t){
const rot = 0.2 + scroll*0.00035; // scroll speeds the spin (slower)
// smooth cursor + parallax
tmx += (mx-tmx)*0.05; tmy += (my-tmy)*0.05;
bh.px += ((bh.x + (tmx-.5)*46*DPR) - bh.px)*0.05;
bh.py += ((bh.y + (tmy-.5)*34*DPR + scroll*0.12) - bh.py)*0.05;
const cx=bh.px, cy=bh.py, R=bh.R*(1+scroll*0.00004);
ctx.clearRect(0,0,W,H);
// fog / nebula haze (drifts slowly)
for(const f of fog){
f.x += f.dx; f.y += f.dy;
if(f.x < -f.r) f.x = W+f.r; if(f.x > W+f.r) f.x = -f.r;
if(f.y < -f.r) f.y = H+f.r; if(f.y > H+f.r) f.y = -f.r;
const g = ctx.createRadialGradient(f.x,f.y,0, f.x,f.y,f.r);
g.addColorStop(0, f.hue + f.a + ')');
g.addColorStop(1, f.hue + '0)');
ctx.beginPath(); ctx.arc(f.x,f.y,f.r,0,7);
ctx.fillStyle=g; ctx.fill();
}
// stars (slow drift + colored twinkle)
for(const s of stars){
s.tw+=0.012; let sy=s.y + s.sp*0.14;
if(sy>H) sy=0;
const a=s.a*(0.5+0.5*Math.sin(s.tw));
ctx.beginPath(); ctx.arc(s.x + (tmx-.5)*30*DPR*s.a, sy + (tmy-.5)*22*DPR*s.a, s.r, 0, 7);
ctx.fillStyle=`rgba(${s.c},${a})`; ctx.fill();
}
// accretion disk (additive) — fire, dimmer
ctx.globalCompositeOperation='lighter';
const outerR = R*2.7;
// soft radiant base glow
const bgg = ctx.createRadialGradient(cx,cy,R*0.3, cx,cy,outerR);
bgg.addColorStop(0,'rgba(255,140,50,0.14)');
bgg.addColorStop(0.5,'rgba(255,85,30,0.07)');
bgg.addColorStop(1,'rgba(255,50,20,0)');
ctx.beginPath(); ctx.arc(cx,cy,outerR,0,7);
ctx.fillStyle=bgg; ctx.fill();
// continuous fire disk band (donut) — solid fire presence
const dg = ctx.createRadialGradient(cx,cy,R*0.95, cx,cy,outerR);
dg.addColorStop(0,'rgba(255,170,60,0.0)');
dg.addColorStop(0.12,'rgba(255,180,70,0.22)');
dg.addColorStop(0.45,'rgba(255,120,40,0.13)');
dg.addColorStop(1,'rgba(255,70,25,0.0)');
ctx.beginPath(); ctx.arc(cx,cy,outerR,0,7);
ctx.fillStyle=dg; ctx.fill();
for(const p of parts){
// Keplerian: angular velocity ∝ r^-1.5
const w = p.k * Math.pow(p.r/R, -1.5) * rot * 0.03;
p.a += w;
p.r *= (1 - 0.00005); // slower accretion
if(p.r < R*1.05) p.r = R*(1.15 + Math.random()*1.3); // respawn
let x = cx + Math.cos(p.a)*p.r;
let y = cy + Math.sin(p.a)*p.r;
// cursor gravity: bend nearby particles toward the cursor
const cdx = mx*W - x, cdy = my*H - y;
const cd2 = cdx*cdx + cdy*cdy;
const cr = R*2.3;
if(cd2 < cr*cr){
const f = (1 - Math.sqrt(cd2)/cr) * 0.3;
x += cdx*f; y += cdy*f;
}
// heat = closer to horizon = hotter
const heat = 1 - Math.max(0, Math.min(1, (p.r/R - 1.1)/1.35));
// doppler beaming: approaching side (velocity toward viewer) brighter
const beam = 0.55 + 0.45*Math.max(0, Math.cos(p.a + 1.2));
// flicker for flame texture
const fl = 0.85 + 0.3*Math.sin(p.fl + t*0.002*p.fs);
const alpha = p.o * (0.35 + 0.65*heat) * beam * fl;
ctx.beginPath();
ctx.arc(x, y, p.s*(0.6+heat*0.9)*fl, 0, 7);
ctx.fillStyle = fireColor(heat, alpha*0.95);
ctx.fill();
}
// photon ring (softened)
const gr = ctx.createRadialGradient(cx,cy,R*0.98, cx,cy,R*1.16);
gr.addColorStop(0,'rgba(255,210,160,0)');
gr.addColorStop(0.5,'rgba(255,190,130,0.68)');
gr.addColorStop(1,'rgba(255,110,50,0)');
ctx.beginPath(); ctx.arc(cx,cy,R*1.07,0,7);
ctx.fillStyle=gr; ctx.fill();
// polar jets (fire tendrils, softened + slower)
for(const j of jets){
j.t += 0.015*j.sp;
j.off += 0.012;
const ang = j.t;
const spread = 0.06 + Math.sin(j.off)*0.03;
const len = j.len * R * (1.4 + 0.4*Math.sin(j.off));
const bx = cx + Math.sin(ang)*spread*R;
const by = cy + j.d*len;
const g = ctx.createLinearGradient(cx,cy,bx,by);
g.addColorStop(0,'rgba(255,180,110,0.28)');
g.addColorStop(1,'rgba(255,90,30,0)');
ctx.strokeStyle=g; ctx.lineWidth=DPR*1.2;
ctx.beginPath(); ctx.moveTo(cx,cy); ctx.lineTo(bx,by); ctx.stroke();
}
ctx.globalCompositeOperation='source-over';
// event horizon (dark disc, sits over the far side of the disk)
const hg = ctx.createRadialGradient(cx,cy,0, cx,cy,R);
hg.addColorStop(0,'rgba(0,0,0,1)');
hg.addColorStop(0.82,'rgba(0,0,0,1)');
hg.addColorStop(1,'rgba(0,0,0,0)');
ctx.beginPath(); ctx.arc(cx,cy,R,0,7);
ctx.fillStyle=hg; ctx.fill();
// faint lens glow toward cursor
const lx=mx*W, ly=my*H;
if(Math.hypot(lx-cx,ly-cy) < R*3.4){
const lg=ctx.createRadialGradient(lx,ly,0,lx,ly,R*0.7);
lg.addColorStop(0,'rgba(255,170,100,0.07)');
lg.addColorStop(1,'rgba(255,170,100,0)');
ctx.beginPath(); ctx.arc(lx,ly,R*0.7,0,7);
ctx.fillStyle=lg; ctx.fill();
}
requestAnimationFrame(draw);
}
addEventListener('mousemove',e=>{ mx=e.clientX/innerWidth; my=e.clientY/innerHeight; });
addEventListener('scroll',()=>{ scroll=window.scrollY||document.documentElement.scrollTop; },{passive:true});
addEventListener('resize',resize);
resize();
requestAnimationFrame(draw);
/* ── typewriter ── */
const lines=[
'$ whoami — self-taught generalist',
'$ uptime — homelab 24/7',
'$ ls /services — 69 live',
'$ ssh nightmare — 4080 ready',
];
let li=0,ci=0,del=false;
(function type(){
const el=document.getElementById('typewriter');
const line=lines[li];
if(!del){ci++;if(ci>line.length){del=true;setTimeout(type,1800);return}}
else{ci--;if(ci<0){del=false;ci=0;li=(li+1)%lines.length}}
el.textContent=line.slice(0,ci);
setTimeout(type,del?22:50);
})();
/* ── reveal on scroll ── */
const io=new IntersectionObserver(es=>es.forEach(e=>{if(e.isIntersecting){e.target.classList.add('in');io.unobserve(e.target)}}),{threshold:.12});
document.querySelectorAll('.reveal').forEach(el=>io.observe(el));
/* ── card glow follows cursor (gentle) ── */
document.querySelectorAll('[data-tilt]').forEach(card=>{
card.addEventListener('mousemove',e=>{
const r=card.getBoundingClientRect();
const mxr=(e.clientX-r.left)/r.width, myr=(e.clientY-r.top)/r.height;
card.style.setProperty('--mx',(mxr*100)+'%'); card.style.setProperty('--my',(myr*100)+'%');
});
});
</script>
</body>
</html>

View File

@@ -0,0 +1,7 @@
server {
listen 5097;
server_name _;
root /var/www/portfolio;
index index.html;
add_header Cache-Control "no-store" always;
}