<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>oxo-call — Model-intelligent orchestration for CLI bioinformatics</title>
<meta name="description" content="Describe your bioinformatics task in plain language. oxo-call fetches tool documentation, grounds it with a built-in skill, and asks your LLM backend to generate the exact flags you need." />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&family=Inter:wght@400;500;600&display=swap" rel="stylesheet" />
<style>
:root {
--bg: #0d1117;
--surface: #161b22;
--border: #30363d;
--accent: #58a6ff;
--accent2: #3fb950;
--accent3: #f78166;
--accent4: #d2a8ff;
--muted: #8b949e;
--text: #e6edf3;
--text-dim: #c9d1d9;
--header-h: 56px;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
background: var(--bg);
color: var(--text);
font-family: 'Inter', system-ui, sans-serif;
font-size: 15px;
line-height: 1.6;
min-height: 100vh;
}
nav {
position: sticky;
top: 0;
z-index: 100;
height: var(--header-h);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
background: rgba(13, 17, 23, 0.85);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border);
}
.nav-logo {
font-family: 'JetBrains Mono', monospace;
font-size: 1.1rem;
font-weight: 700;
color: var(--accent);
text-decoration: none;
letter-spacing: -0.5px;
}
.nav-logo span { color: var(--accent2); }
.nav-links {
display: flex;
gap: 1.5rem;
list-style: none;
align-items: center;
}
.nav-links a {
color: var(--muted);
text-decoration: none;
font-size: 0.875rem;
transition: color 0.15s;
}
.nav-links a:hover { color: var(--text); }
.btn {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.45rem 1rem;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 500;
text-decoration: none;
transition: opacity 0.15s, transform 0.1s;
cursor: pointer;
border: none;
}
.btn:hover { opacity: 0.85; transform: translateY(-1px); }
.btn-primary { background: var(--accent); color: #0d1117; }
.btn-secondary { background: transparent; color: var(--text); border: 1px solid var(--border); }
.btn-sm { padding: 0.3rem 0.75rem; font-size: 0.8rem; }
.hero {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 3rem;
align-items: center;
max-width: 1200px;
margin: 0 auto;
padding: 5rem 2rem 4rem;
}
.hero-text h1 {
font-size: clamp(2rem, 4vw, 3rem);
font-weight: 700;
line-height: 1.2;
letter-spacing: -0.5px;
margin-bottom: 1.25rem;
}
.hero-text h1 em {
font-style: normal;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero-text p {
color: var(--text-dim);
font-size: 1.05rem;
margin-bottom: 2rem;
max-width: 480px;
}
.hero-actions { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.term-window {
background: #010409;
border: 1px solid var(--border);
border-radius: 10px;
overflow: hidden;
box-shadow: 0 20px 60px rgba(0,0,0,0.5);
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
}
.term-titlebar {
background: var(--surface);
border-bottom: 1px solid var(--border);
padding: 0.6rem 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.dot { width: 12px; height: 12px; border-radius: 50%; }
.dot-r { background: #ff5f57; }
.dot-y { background: #febc2e; }
.dot-g { background: #28c840; }
.term-title {
flex: 1;
text-align: center;
color: var(--muted);
font-size: 0.75rem;
}
.term-body {
padding: 1.2rem 1.4rem;
min-height: 280px;
line-height: 1.7;
}
.term-line { display: block; }
.prompt { color: var(--accent2); }
.cmd { color: var(--text); }
.output { color: var(--muted); }
.flag { color: var(--accent4); }
.tool { color: var(--accent); }
.success { color: var(--accent2); }
.warn { color: #e3b341; }
.cursor {
display: inline-block;
width: 8px;
height: 1.1em;
background: var(--accent);
vertical-align: text-bottom;
animation: blink 1s step-end infinite;
}
@keyframes blink { 50% { opacity: 0; } }
.badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 1.5rem;
}
.badge {
display: inline-flex;
align-items: center;
gap: 0.3rem;
padding: 0.2rem 0.6rem;
border-radius: 20px;
font-size: 0.72rem;
font-family: 'JetBrains Mono', monospace;
border: 1px solid var(--border);
color: var(--muted);
}
section {
max-width: 1200px;
margin: 0 auto;
padding: 4rem 2rem;
}
.section-label {
font-family: 'JetBrains Mono', monospace;
font-size: 0.75rem;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--accent);
margin-bottom: 0.75rem;
}
.section-title {
font-size: clamp(1.4rem, 3vw, 2rem);
font-weight: 700;
margin-bottom: 1rem;
}
.section-body {
color: var(--text-dim);
max-width: 560px;
margin-bottom: 2.5rem;
}
hr.divider {
border: none;
border-top: 1px solid var(--border);
margin: 0;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.25rem;
}
.feature-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.4rem;
transition: border-color 0.2s, transform 0.15s;
}
.feature-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.feature-icon { font-size: 1.5rem; margin-bottom: 0.75rem; }
.feature-card h3 { font-size: 0.95rem; font-weight: 600; margin-bottom: 0.4rem; }
.feature-card p { font-size: 0.85rem; color: var(--muted); line-height: 1.5; }
.tools-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
grid-template-rows: repeat(2, auto);
gap: 1rem;
max-height: 340px;
overflow: hidden;
overflow: hidden;
perspective: 1000px;
position: relative;
}
.tools-grid::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 80px;
background: linear-gradient(to bottom, transparent, var(--bg));
pointer-events: none;
z-index: 5;
}
.tool-card {
background: linear-gradient(135deg, var(--surface) 0%, rgba(88,166,255,0.03) 100%);
border: 1px solid var(--border);
border-radius: 12px;
padding: 1.2rem 1rem;
font-family: 'JetBrains Mono', monospace;
cursor: pointer;
position: relative;
overflow: hidden;
transform-style: preserve-3d;
transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
animation:
toolFloat 6s ease-in-out infinite,
toolGlow 4s ease-in-out infinite,
toolPulse 8s ease-in-out infinite;
}
.tool-card::before {
content: '';
position: absolute;
top: -50%;
left: -50%;
width: 200%;
height: 200%;
background: linear-gradient(
45deg,
transparent 30%,
rgba(88,166,255,0.03) 50%,
transparent 70%
);
animation: shimmer 6s linear infinite;
pointer-events: none;
}
.tool-card::after {
content: '';
position: absolute;
inset: 0;
border-radius: 12px;
padding: 1px;
background: linear-gradient(135deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
opacity: 0;
transition: opacity 0.3s;
animation: borderRotate 4s linear infinite;
}
.tool-card:nth-child(1) { animation-delay: 0s, 0s, 0s; }
.tool-card:nth-child(2) { animation-delay: 0.15s, 0.5s, 0.3s; }
.tool-card:nth-child(3) { animation-delay: 0.3s, 1s, 0.6s; }
.tool-card:nth-child(4) { animation-delay: 0.45s, 1.5s, 0.9s; }
.tool-card:nth-child(5) { animation-delay: 0.6s, 2s, 1.2s; }
.tool-card:nth-child(6) { animation-delay: 0.75s, 2.5s, 1.5s; }
.tool-card:nth-child(7) { animation-delay: 0.9s, 3s, 1.8s; }
.tool-card:nth-child(8) { animation-delay: 1.05s, 0s, 2.1s; }
.tool-card:nth-child(9) { animation-delay: 1.2s, 0.5s, 2.4s; }
.tool-card:nth-child(10) { animation-delay: 1.35s, 1s, 2.7s; }
.tool-card:nth-child(11) { animation-delay: 1.5s, 1.5s, 0s; }
.tool-card:nth-child(12) { animation-delay: 1.65s, 2s, 0.3s; }
.tool-card:nth-child(13) { animation-delay: 1.8s, 2.5s, 0.6s; }
.tool-card:nth-child(14) { animation-delay: 1.95s, 3s, 0.9s; }
.tool-card:nth-child(15) { animation-delay: 2.1s, 0s, 1.2s; }
.tool-card:nth-child(16) { animation-delay: 2.25s, 0.5s, 1.5s; }
.tool-card:nth-child(17) { animation-delay: 2.4s, 1s, 1.8s; }
.tool-card:nth-child(18) { animation-delay: 2.55s, 1.5s, 2.1s; }
.tool-card:nth-child(19) { animation-delay: 2.7s, 2s, 2.4s; }
.tool-card:nth-child(20) { animation-delay: 2.85s, 2.5s, 2.7s; }
.tool-card:nth-child(21) { animation-delay: 3s, 3s, 0s; }
.tool-card:nth-child(22) { animation-delay: 3.15s, 0s, 0.3s; }
.tool-card:nth-child(23) { animation-delay: 3.3s, 0.5s, 0.6s; }
.tool-card:nth-child(24) { animation-delay: 3.45s, 1s, 0.9s; }
.tool-card:nth-child(25) { animation-delay: 3.6s, 1.5s, 1.2s; }
.tool-card:nth-child(26) { animation-delay: 3.75s, 2s, 1.5s; }
.tool-card:nth-child(27) { animation-delay: 3.9s, 2.5s, 1.8s; }
.tool-card:nth-child(28) { animation-delay: 4.05s, 3s, 2.1s; }
@keyframes toolFloat {
0%, 100% { transform: translateY(0) rotateX(0deg); }
25% { transform: translateY(-6px) rotateX(2deg); }
50% { transform: translateY(-3px) rotateX(0deg); }
75% { transform: translateY(-8px) rotateX(-2deg); }
}
@keyframes toolGlow {
0%, 100% {
box-shadow: 0 2px 8px rgba(88,166,255,0), inset 0 1px 0 rgba(255,255,255,0.02);
border-color: var(--border);
}
50% {
box-shadow: 0 4px 20px rgba(88,166,255,0.15), inset 0 1px 0 rgba(255,255,255,0.05);
border-color: rgba(88,166,255,0.4);
}
}
@keyframes toolPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.85; }
}
@keyframes shimmer {
0% { transform: translateX(-100%) translateY(-100%) rotate(45deg); }
100% { transform: translateX(100%) translateY(100%) rotate(45deg); }
}
@keyframes borderRotate {
0% { background: linear-gradient(0deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0)); }
25% { background: linear-gradient(90deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0)); }
50% { background: linear-gradient(180deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0)); }
75% { background: linear-gradient(270deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0)); }
100% { background: linear-gradient(360deg, rgba(88,166,255,0), rgba(88,166,255,0.3), rgba(63,185,80,0)); }
}
.tool-card:hover {
transform: translateY(-12px) scale(1.05) rotateX(5deg);
border-color: var(--accent);
background: linear-gradient(135deg, rgba(88,166,255,0.15) 0%, var(--surface) 100%);
box-shadow:
0 20px 40px rgba(88,166,255,0.2),
0 0 30px rgba(88,166,255,0.1),
inset 0 1px 0 rgba(255,255,255,0.1);
z-index: 10;
animation-play-state: paused;
}
.tool-card:hover::after {
opacity: 1;
}
.tool-card:hover::before {
animation-duration: 2s;
}
.tool-name {
font-size: 0.95rem;
font-weight: 700;
background: linear-gradient(135deg, var(--accent), var(--accent2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin-bottom: 0.4rem;
position: relative;
z-index: 1;
}
.tool-desc {
font-size: 0.75rem;
color: var(--muted);
font-family: 'Inter', sans-serif;
position: relative;
z-index: 1;
}
.tool-icon {
font-size: 1.8rem;
margin-bottom: 0.5rem;
opacity: 0.9;
filter: drop-shadow(0 2px 8px rgba(88,166,255,0.25));
animation: iconPulse 3s ease-in-out infinite;
display: inline-block;
}
@keyframes iconPulse {
0%, 100% { transform: scale(1); filter: drop-shadow(0 2px 8px rgba(88,166,255,0.25)); }
50% { transform: scale(1.1); filter: drop-shadow(0 4px 12px rgba(88,166,255,0.4)); }
}
.tool-card:nth-child(2n) .tool-icon { animation-delay: 0.5s; }
.tool-card:nth-child(3n) .tool-icon { animation-delay: 1s; }
.tool-card:nth-child(5n) .tool-icon { animation-delay: 1.5s; }
.tool-card:nth-child(7n) .tool-icon { animation-delay: 2s; }
.demo-wrapper {
display: grid;
grid-template-columns: 280px 1fr;
gap: 1.5rem;
align-items: start;
}
.demo-sidebar {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.demo-sidebar-title {
padding: 0.75rem 1rem;
font-size: 0.75rem;
font-family: 'JetBrains Mono', monospace;
color: var(--muted);
border-bottom: 1px solid var(--border);
text-transform: uppercase;
letter-spacing: 0.08em;
}
.demo-example {
padding: 0.8rem 1rem;
border-bottom: 1px solid var(--border);
cursor: pointer;
transition: background 0.15s;
}
.demo-example:last-child { border-bottom: none; }
.demo-example:hover { background: rgba(88,166,255,0.05); }
.demo-example.active { background: rgba(88,166,255,0.1); border-left: 2px solid var(--accent); }
.demo-ex-tool { font-family: 'JetBrains Mono', monospace; font-size: 0.82rem; color: var(--accent); font-weight: 600; }
.demo-ex-task { font-size: 0.78rem; color: var(--muted); margin-top: 0.25rem; }
.demo-terminal {
background: #010409;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.demo-term-body {
padding: 1.25rem 1.5rem;
min-height: 320px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
line-height: 1.8;
}
.code-block {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
margin-bottom: 1rem;
}
.code-block-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem 1rem;
border-bottom: 1px solid var(--border);
font-size: 0.75rem;
color: var(--muted);
}
pre {
margin: 0;
padding: 1rem 1.25rem;
overflow-x: auto;
font-family: 'JetBrains Mono', monospace;
font-size: 0.82rem;
line-height: 1.7;
color: var(--text-dim);
}
pre .c { color: var(--muted); font-style: italic; }
pre .k { color: var(--accent4); }
pre .s { color: var(--accent2); }
footer {
border-top: 1px solid var(--border);
padding: 2rem;
text-align: center;
color: var(--muted);
font-size: 0.82rem;
}
footer a { color: var(--accent); text-decoration: none; }
footer a:hover { text-decoration: underline; }
.copy-btn {
background: transparent;
border: 1px solid var(--border);
border-radius: 4px;
color: var(--muted);
cursor: pointer;
padding: 0.2rem 0.5rem;
font-size: 0.72rem;
font-family: 'JetBrains Mono', monospace;
transition: border-color 0.15s, color 0.15s;
}
.copy-btn:hover { border-color: var(--accent); color: var(--accent); }
.copy-btn.copied { border-color: var(--accent2); color: var(--accent2); }
@media (max-width: 900px) {
.hero { grid-template-columns: 1fr; gap: 2rem; }
.demo-wrapper { grid-template-columns: 1fr; }
.demo-sidebar { display: none; }
}
@media (max-width: 600px) {
nav { padding: 0 1rem; }
section { padding: 2.5rem 1rem; }
.hero { padding: 3rem 1rem 2rem; }
.nav-links { display: none; }
}
.community-banner {
background: linear-gradient(135deg, rgba(88,166,255,0.08), rgba(63,185,80,0.06));
border: 1px solid rgba(88,166,255,0.25);
border-radius: 12px;
padding: 2.5rem 2rem;
display: grid;
grid-template-columns: 1fr auto;
gap: 2rem;
align-items: center;
}
.community-banner h2 {
font-size: clamp(1.2rem, 2.5vw, 1.6rem);
font-weight: 700;
margin-bottom: 0.5rem;
}
.community-banner p {
color: var(--text-dim);
font-size: 0.9rem;
max-width: 560px;
margin-bottom: 1.25rem;
}
.community-actions {
display: flex;
flex-wrap: wrap;
gap: 0.6rem;
}
.community-links {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 0.6rem;
min-width: 240px;
}
.community-link {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.55rem 0.9rem;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
text-decoration: none;
font-size: 0.82rem;
color: var(--text-dim);
transition: border-color 0.15s, color 0.15s;
white-space: nowrap;
}
.community-link:hover { border-color: var(--accent); color: var(--accent); }
.community-link .emoji { font-size: 1rem; }
@media (max-width: 800px) {
.community-banner { grid-template-columns: 1fr; }
.community-links { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 500px) {
.community-links { grid-template-columns: 1fr; }
}
.wasm-badge {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.2rem 0.7rem;
background: rgba(88,166,255,0.1);
border: 1px solid rgba(88,166,255,0.3);
border-radius: 20px;
font-family: 'JetBrains Mono', monospace;
font-size: 0.72rem;
color: var(--accent);
margin-bottom: 1rem;
}
.pulse {
width: 6px; height: 6px;
background: var(--accent2);
border-radius: 50%;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.4; transform: scale(0.7); }
}
.arch-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 0;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.arch-step {
padding: 1.25rem;
text-align: center;
border-right: 1px solid var(--border);
}
.arch-step:last-child { border-right: none; }
.arch-step-icon { font-size: 1.5rem; margin-bottom: 0.5rem; }
.arch-step-title { font-size: 0.78rem; font-weight: 600; color: var(--text); margin-bottom: 0.3rem; }
.arch-step-desc { font-size: 0.7rem; color: var(--muted); }
@media (max-width: 800px) {
.arch-grid { grid-template-columns: 1fr 1fr; }
.arch-step { border-right: none; border-bottom: 1px solid var(--border); }
.arch-step:last-child { border-bottom: none; }
}
.bench-tabs {
display: flex;
gap: 0.5rem;
margin-bottom: 1.5rem;
flex-wrap: wrap;
}
.bench-tab {
padding: 0.4rem 1rem;
border-radius: 20px;
font-size: 0.8rem;
font-family: 'JetBrains Mono', monospace;
border: 1px solid var(--border);
color: var(--muted);
background: transparent;
cursor: pointer;
transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.bench-tab:hover { border-color: var(--accent); color: var(--accent); }
.bench-tab.active {
border-color: var(--accent);
color: var(--accent);
background: rgba(88,166,255,0.1);
}
.bench-panel { display: none; }
.bench-panel.active { display: block; }
.bench-table-wrap {
overflow-x: auto;
border: 1px solid var(--border);
border-radius: 8px;
}
.bench-table {
width: 100%;
border-collapse: collapse;
font-family: 'JetBrains Mono', monospace;
font-size: 0.8rem;
}
.bench-table thead tr {
background: var(--surface);
border-bottom: 1px solid var(--border);
}
.bench-table th {
padding: 0.6rem 1rem;
text-align: left;
color: var(--accent);
font-weight: 600;
white-space: nowrap;
}
.bench-table td {
padding: 0.55rem 1rem;
color: var(--text-dim);
border-bottom: 1px solid var(--border);
white-space: nowrap;
}
.bench-table tbody tr:last-child td { border-bottom: none; }
.bench-table tbody tr:hover { background: rgba(88,166,255,0.04); }
.bench-num { color: var(--text); text-align: right; }
.bench-ok { color: var(--accent2); }
.bench-badge-assay {
display: inline-block;
padding: 0.15rem 0.5rem;
border-radius: 12px;
font-size: 0.72rem;
border: 1px solid var(--border);
color: var(--muted);
}
.bench-cat {
display: inline-block;
padding: 0.15rem 0.5rem;
border-radius: 12px;
font-size: 0.72rem;
border: 1px solid var(--border);
color: var(--accent4);
}
#eval-table {
width: 100%;
}
#eval-table colgroup col:nth-child(1) {
width: 12%;
}
#eval-table colgroup col:nth-child(2) {
width: 10%;
}
#eval-table colgroup col:nth-child(3) {
width: 48%;
}
#eval-table colgroup col:nth-child(4) {
width: 30%;
}
#eval-table th {
vertical-align: middle;
padding: 0.6rem 0.8rem;
white-space: nowrap;
}
#eval-table td {
vertical-align: top;
padding: 0.6rem 0.8rem;
}
#eval-table td:nth-child(3) {
word-break: break-word;
line-height: 1.5;
}
#eval-table td:nth-child(4) {
word-break: break-word;
line-height: 1.4;
color: var(--muted);
}
.bench-note {
font-size: 0.78rem;
color: var(--muted);
margin-top: 1rem;
font-family: 'Inter', sans-serif;
}
.bench-note code {
font-family: 'JetBrains Mono', monospace;
font-size: 0.76rem;
background: var(--surface);
padding: 0.1rem 0.3rem;
border-radius: 3px;
border: 1px solid var(--border);
}
.bench-loading { color: var(--muted); font-size: 0.85rem; padding: 1.5rem 0; }
.paypal-section {
margin-top: 2rem;
border: 1px solid var(--border);
border-radius: 8px;
overflow: hidden;
}
.paypal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.25rem;
background: var(--surface);
cursor: pointer;
transition: background 0.15s;
}
.paypal-header:hover {
background: rgba(88, 166, 255, 0.05);
}
.paypal-title {
display: flex;
align-items: center;
gap: 0.75rem;
font-weight: 600;
color: var(--text);
}
.paypal-icon {
font-size: 1.25rem;
}
.paypal-toggle {
color: var(--muted);
font-size: 0.9rem;
transition: transform 0.2s;
}
.paypal-section.open .paypal-toggle {
transform: rotate(180deg);
}
.paypal-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
.paypal-section.open .paypal-content {
max-height: 500px;
}
.paypal-inner {
padding: 1.5rem;
display: grid;
grid-template-columns: 200px 1fr;
gap: 2rem;
align-items: start;
}
.paypal-qr {
text-align: center;
}
.paypal-qr img {
width: 180px;
height: 180px;
border-radius: 8px;
border: 1px solid var(--border);
}
.paypal-info h4 {
margin: 0 0 0.75rem 0;
color: var(--accent);
font-size: 0.95rem;
}
.paypal-info p {
margin: 0 0 0.5rem 0;
color: var(--text-dim);
font-size: 0.85rem;
line-height: 1.6;
}
.paypal-info .price {
font-size: 1.5rem;
font-weight: 700;
color: var(--accent2);
margin: 0.5rem 0;
}
.paypal-note {
margin-top: 1rem;
padding: 0.75rem 1rem;
background: rgba(243, 166, 88, 0.1);
border-left: 3px solid var(--accent3);
border-radius: 0 4px 4px 0;
font-size: 0.8rem;
color: var(--text-dim);
}
@media (max-width: 600px) {
.paypal-inner {
grid-template-columns: 1fr;
text-align: center;
}
.paypal-qr img {
width: 160px;
height: 160px;
}
}
</style>
</head>
<body>
<nav>
<a class="nav-logo" href="#">oxo<span>-call</span></a>
<ul class="nav-links">
<li><a href="#features">Features</a></li>
<li><a href="#demo">Demos</a></li>
<li><a href="#tools">Skills</a></li>
<li><a href="#job">Jobs</a></li>
<li><a href="#workflow">Workflows</a></li>
<li><a href="#benchmarks">Benchmarks</a></li>
<li><a href="#community">Community</a></li>
<li><a href="#install">Install</a></li>
<li><a href="documentation/index.html">Docs</a></li>
<li><a href="https://github.com/Traitome/oxo-call" target="_blank" rel="noopener">GitHub</a></li>
</ul>
<a href="https://github.com/Traitome/oxo-call" class="btn btn-primary btn-sm" target="_blank" rel="noopener">
★ Star on GitHub
</a>
</nav>
<div class="hero">
<div class="hero-text">
<div class="badges">
<span class="badge">🦀 Rust 2024</span>
<span class="badge">🧬 Bioinformatics</span>
<span class="badge">🤖 LLM-powered</span>
<span class="badge">⚡ WebAssembly</span>
</div>
<h1>Model-intelligent<br/>orchestration for<br/><em>CLI bioinformatics</em></h1>
<p>
Describe your task in plain language — oxo-call fetches the tool's
documentation, grounds the request with a built-in skill, and asks your
LLM backend to generate the exact flags you need.
</p>
<div class="hero-actions">
<a href="#install" class="btn btn-primary">Get started</a>
<a href="documentation/index.html" class="btn btn-secondary">Documentation</a>
<a href="#demo" class="btn btn-secondary">Show demos</a>
<a href="https://github.com/Traitome/oxo-call" class="btn btn-secondary" target="_blank" rel="noopener">GitHub →</a>
</div>
</div>
<div class="term-window" id="hero-term">
<div class="term-titlebar">
<span class="dot dot-r"></span>
<span class="dot dot-y"></span>
<span class="dot dot-g"></span>
<span class="term-title">bash — oxo-call</span>
</div>
<div class="term-body" id="hero-term-body">
<span class="term-line"><span class="prompt">$ </span><span id="hero-typing"></span><span class="cursor" id="hero-cursor"></span></span>
</div>
</div>
</div>
<hr class="divider" />
<section>
<div class="section-label">// architecture</div>
<div class="arch-grid">
<div class="arch-step">
<div class="arch-step-icon">💬</div>
<div class="arch-step-title">Natural Language</div>
<div class="arch-step-desc">Describe your task</div>
</div>
<div class="arch-step">
<div class="arch-step-icon">📚</div>
<div class="arch-step-title">Docs Layer</div>
<div class="arch-step-desc">--help · cache · remote URL · local files</div>
</div>
<div class="arch-step">
<div class="arch-step-icon">🎯</div>
<div class="arch-step-title">Skill System</div>
<div class="arch-step-desc">built-in → community → user</div>
</div>
<div class="arch-step">
<div class="arch-step-icon">🤖</div>
<div class="arch-step-title">LLM Backend</div>
<div class="arch-step-desc">Copilot · OpenAI · Ollama</div>
</div>
<div class="arch-step">
<div class="arch-step-icon">⚙️</div>
<div class="arch-step-title">Command</div>
<div class="arch-step-desc">run · dry-run · --ask</div>
</div>
</div>
</section>
<hr class="divider" />
<section id="features">
<div class="section-label">// features</div>
<h2 class="section-title">Everything you need to stop<br/>remembering flags</h2>
<p class="section-body">
oxo-call wraps the full command-generation workflow — from fetching live
documentation to grounding the LLM with expert skills — into a single
two-word command.
</p>
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">🧠</div>
<h3>LLM-powered parameter generation</h3>
<p>Describe what you want in plain English. The model generates the right flags, grounded in the actual tool documentation.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📚</div>
<h3>Automatic documentation fetching</h3>
<p>Grabs <code>--help</code> output and optionally fetches remote docs or man pages. Works even if the tool isn't installed locally.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔍</div>
<h3>Dry-run mode</h3>
<p>Preview the exact command that would be executed before committing. Never accidentally overwrite files again.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎯</div>
<h3>Built-in skill system</h3>
<p>Expert knowledge for 159 tools baked in as skill files — bioinformatics, HPC schedulers, containers, and more, with real examples and pitfalls ready for practical use.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔗</div>
<h3>Native workflow engine</h3>
<p>Run <code>.oxo.toml</code> pipelines natively — DAG parallelism, wildcard expansion, output caching. Export to <strong>Snakemake</strong> or <strong>Nextflow</strong> for HPC compatibility.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔧</div>
<h3>Flexible LLM backends</h3>
<p>GitHub Copilot (default), OpenAI, Anthropic, or a local Ollama instance — switch with one config key.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📜</div>
<h3>Command history</h3>
<p>Every run is logged as JSONL with exit code, timestamp, and generated command. Filter by tool for quick lookup.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🗂️</div>
<h3>Auto documentation cache</h3>
<p>Tool help is fetched and cached automatically on first use. Enrich with remote URLs, local files, or directories via <code>oxo-call docs add</code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🖥️</div>
<h3>Remote server management</h3>
<p>Register workstations and HPC clusters via SSH. Generate commands for remote execution with login-node safety checks and scheduler integration (Slurm, PBS, SGE, LSF).</p>
</div>
<div class="feature-card">
<div class="feature-icon">🏗️</div>
<h3>HPC cluster skills</h3>
<p>Built-in skills for Slurm, PBS, SGE, LSF, HTCondor, and Kubernetes — job templates, resource queries, and array job patterns for quick HPC script generation.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📋</div>
<h3>Job library with lifecycle management</h3>
<p>Save named shell shortcuts (<code>oxo-call job add</code>), attach cron schedules, track run history and exit codes, and generate jobs from plain-English descriptions via the LLM. 25+ built-in templates for common ops, HPC, and bioinformatics tasks.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔀</div>
<h3>Variable interpolation & batch execution</h3>
<p>Use <code>--var KEY=VALUE</code> for custom placeholders, <code>{item}</code> for batch input, and <code>-j N</code> for parallel execution. Process hundreds of files with a single command.</p>
</div>
</div>
</section>
<hr class="divider" />
<section id="demo">
<div class="section-label">// interactive demo</div>
<h2 class="section-title">See it in action</h2>
<p class="section-body">
Click an example to watch oxo-call ground the task in documentation,
load the matching skill, and produce the exact command arguments.
</p>
<div class="wasm-badge">
<span class="pulse"></span>
JS simulation · powered by the same prompt logic as the WASI binary
</div>
<div class="demo-wrapper">
<div class="demo-sidebar">
<div class="demo-sidebar-title">// examples</div>
<div class="demo-example active" data-idx="0">
<div class="demo-ex-tool">samtools sort</div>
<div class="demo-ex-task">sort BAM by coordinate → sorted.bam</div>
</div>
<div class="demo-example" data-idx="1">
<div class="demo-ex-tool">bwa mem</div>
<div class="demo-ex-task">align paired reads, 16 threads</div>
</div>
<div class="demo-example" data-idx="2">
<div class="demo-ex-tool">bcftools call</div>
<div class="demo-ex-task">call variants from BAM</div>
</div>
<div class="demo-example" data-idx="3">
<div class="demo-ex-tool">fastp</div>
<div class="demo-ex-task">trim adapters, paired-end</div>
</div>
<div class="demo-example" data-idx="4">
<div class="demo-ex-tool">minimap2</div>
<div class="demo-ex-task">long-read genome alignment</div>
</div>
<div class="demo-example" data-idx="5">
<div class="demo-ex-tool">seqkit stats</div>
<div class="demo-ex-task">basic stats on a FASTQ file</div>
</div>
<div class="demo-example" data-idx="6">
<div class="demo-ex-tool">variable interpolation</div>
<div class="demo-ex-task">batch process with {item} and --var</div>
</div>
</div>
<div class="demo-terminal">
<div class="term-titlebar">
<span class="dot dot-r"></span>
<span class="dot dot-y"></span>
<span class="dot dot-g"></span>
<span class="term-title" id="demo-term-title">oxo-call dry-run</span>
</div>
<div class="demo-term-body" id="demo-body">
</div>
</div>
</div>
</section>
<hr class="divider" />
<section id="tools">
<div class="section-label">// built-in skills</div>
<h2 class="section-title">Expert knowledge for 159 tools</h2>
<p class="section-body">
Each built-in skill encodes domain-specific concepts, common pitfalls, and
worked examples so the LLM is guided beyond a raw <code>--help</code> dump.
</p>
<div class="tools-grid" id="tools-grid">
<div class="tool-card" data-tool="samtools"><div class="tool-icon">🧬</div><div class="tool-name">samtools</div><div class="tool-desc">SAM/BAM/CRAM manipulation</div></div>
<div class="tool-card" data-tool="bwa"><div class="tool-icon">🎯</div><div class="tool-name">bwa</div><div class="tool-desc">Burrows-Wheeler short-read aligner</div></div>
<div class="tool-card" data-tool="bcftools"><div class="tool-icon">🧪</div><div class="tool-name">bcftools</div><div class="tool-desc">VCF/BCF variant calling & filtering</div></div>
<div class="tool-card" data-tool="bedtools"><div class="tool-icon">🛏️</div><div class="tool-name">bedtools</div><div class="tool-desc">Genomic interval arithmetic</div></div>
<div class="tool-card" data-tool="gatk"><div class="tool-icon">🔬</div><div class="tool-name">gatk</div><div class="tool-desc">Genome Analysis Toolkit</div></div>
<div class="tool-card" data-tool="minimap2"><div class="tool-icon">📏</div><div class="tool-name">minimap2</div><div class="tool-desc">Long-read / splice-aware aligner</div></div>
<div class="tool-card" data-tool="fastp"><div class="tool-icon">✂️</div><div class="tool-name">fastp</div><div class="tool-desc">Adapter trimming & QC</div></div>
<div class="tool-card" data-tool="bowtie2"><div class="tool-icon">🎀</div><div class="tool-name">bowtie2</div><div class="tool-desc">Fast short-read aligner</div></div>
<div class="tool-card" data-tool="seqkit"><div class="tool-icon">🧰</div><div class="tool-name">seqkit</div><div class="tool-desc">FASTA/Q toolkit</div></div>
<div class="tool-card" data-tool="star"><div class="tool-icon">⭐</div><div class="tool-name">star</div><div class="tool-desc">RNA-seq spliced aligner</div></div>
<div class="tool-card" data-tool="slurm"><div class="tool-icon">⚡</div><div class="tool-name">slurm</div><div class="tool-desc">HPC job scheduling (sbatch, srun)</div></div>
<div class="tool-card" data-tool="pbs"><div class="tool-icon">📋</div><div class="tool-name">pbs</div><div class="tool-desc">PBS/Torque batch scheduler (qsub)</div></div>
</div>
</section>
<hr class="divider" />
<section id="job">
<div class="section-label">// job library</div>
<h2 class="section-title">Named command shortcuts —<br/>with scheduling, history, and LLM generation</h2>
<p class="section-body">
<code>oxo-call job</code> is your personal library of named shell commands.
Add any command once, then run it by name — locally or on a remote SSH server.
Track execution history, set cron schedules, and let the LLM generate commands
from plain-English descriptions.
</p>
<div class="features-grid" style="margin-top:2rem">
<div class="feature-card">
<div class="feature-icon">📋</div>
<h3>Named command library</h3>
<p>Save any shell command with <code>oxo-call job add</code>. Attach descriptions and tags. Run it anywhere with <code>oxo-call job run <name></code>.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<h3>Execution history & status</h3>
<p>Every run is recorded with timestamp, exit code, and duration. <code>job status</code> shows a live dashboard; <code>job history</code> shows the full run log.</p>
</div>
<div class="feature-card">
<div class="feature-icon">⏰</div>
<h3>Cron scheduling</h3>
<p>Attach a cron expression with <code>job schedule <name> "0 * * * *"</code> and wire it to your crontab for automated execution.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🤖</div>
<h3>LLM-generated jobs</h3>
<p>Describe a task in plain English — <code>job generate "check disk and alert if over 90%"</code> — and the LLM generates and saves the shell command for you.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🗃️</div>
<h3>25+ built-in templates</h3>
<p>Browse ready-made jobs for SLURM, PBS, LSF, Kubernetes, Docker, Git, and bioinformatics with <code>oxo-call job list --builtin</code>. Import with one command.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🖥️</div>
<h3>Local and remote execution</h3>
<p>Run jobs locally or on any registered SSH server with <code>--server</code>. Integrates with the <code>server</code> subcommand for HPC cluster management.</p>
</div>
</div>
<div class="code-block" style="margin-top:2rem">
<div class="code-block-header">
<span style="color:var(--muted);font-size:0.8rem">// job library commands</span>
<button class="copy-btn" data-copy="oxo-call job import squeue-me && oxo-call job run squeue-me">copy</button>
</div>
<pre class="code-block-body"><span class="c"># Import a built-in SLURM template and run it</span>
<span class="prompt">$</span> oxo-call job list --builtin --tag slurm
<span class="prompt">$</span> oxo-call job import squeue-me
<span class="prompt">$</span> oxo-call job run squeue-me
<span class="c"># Generate a job from a plain-English description</span>
<span class="prompt">$</span> oxo-call job generate <span class="s">"show Docker containers over 1 GB memory"</span>
<span class="c"># View execution history and status</span>
<span class="prompt">$</span> oxo-call job status
<span class="prompt">$</span> oxo-call job history squeue-me</pre>
</div>
</section>
<hr class="divider" />
<section id="workflow">
<div class="section-label">// workflow engine</div>
<h2 class="section-title">Native Rust pipeline execution —<br/>Snakemake & Nextflow as export formats</h2>
<p class="section-body">
<code>oxo-call workflow</code> runs bioinformatics pipelines directly with a
lightweight built-in engine. No Snakemake, Nextflow, or Conda needed.
Export to either format for HPC environments that require them.
</p>
<div class="features-grid" style="margin-top:2rem">
<div class="feature-card">
<div class="feature-icon">⚙️</div>
<h3>Native Rust engine</h3>
<p>Run <code>.oxo.toml</code> workflows directly — no Snakemake or Nextflow required. DAG-based parallelism, wildcard expansion, output caching.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔬</div>
<h3>RNA-seq</h3>
<p>fastp QC → STAR alignment → featureCounts quantification → MultiQC report. Run natively or export to Snakemake/Nextflow DSL2.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🧬</div>
<h3>Whole-Genome Sequencing</h3>
<p>fastp → BWA-MEM2 → GATK MarkDuplicates → BQSR → HaplotypeCaller GVCF. GATK best-practices out of the box.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔓</div>
<h3>ATAC-seq</h3>
<p>fastp → Bowtie2 → Picard deduplication → blacklist filtering → MACS3 peak calling. Ready for downstream footprinting.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🌍</div>
<h3>Shotgun Metagenomics</h3>
<p>fastp → host read removal (Bowtie2) → Kraken2 classification → Bracken species abundance estimation.</p>
</div>
<div class="feature-card">
<div class="feature-icon">✨</div>
<h3>LLM-generated custom workflows</h3>
<p>Describe any pipeline in plain language and get a complete, runnable <code>.oxo.toml</code>. One prompt → one deployable workflow.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔄</div>
<h3>Snakemake & Nextflow export</h3>
<p>Every template can be exported with <code>workflow export --to snakemake</code> or <code>--to nextflow</code> for HPC environments.</p>
</div>
<div class="feature-card">
<div class="feature-icon">📊</div>
<h3>Output freshness caching</h3>
<p>Automatically skip steps whose outputs exist and are newer than inputs. Re-run only what changed — perfect for iterative pipeline development.</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎯</div>
<h3>Gather steps aggregation</h3>
<p>Steps with <code>gather = true</code> run once after all wildcard instances complete. Ideal for MultiQC reports and downstream aggregation tasks.</p>
</div>
</div>
<div class="code-block" style="margin-top:2.5rem">
<div class="code-block-header">
<span style="color:var(--muted);font-size:0.8rem">// workflow commands</span>
</div>
<pre class="code-block-body"><span class="c"># List all built-in templates</span>
<span class="prompt">$</span> oxo-call workflow list
<span class="c"># Preview the RNA-seq pipeline (no execution)</span>
<span class="prompt">$</span> oxo-call workflow dry-run rnaseq
<span class="c"># Run a workflow (native engine — no Snakemake/Nextflow needed)</span>
<span class="prompt">$</span> oxo-call workflow run my_rnaseq.toml
<span class="c"># Export to Snakemake for HPC submission</span>
<span class="prompt">$</span> oxo-call workflow export wgs.toml --to snakemake -o Snakefile
<span class="c"># Generate a custom ChIP-seq workflow with LLM</span>
<span class="prompt">$</span> oxo-call workflow generate \
"ChIP-seq H3K27ac: QC → Bowtie2 → MACS3 peaks vs input control" \
-o chipseq.toml</pre>
</div>
</section>
<hr class="divider" />
<section id="benchmarks">
<div class="section-label">// benchmarks</div>
<h2 class="section-title">Reproducible omics evaluation —<br/>rigorous, open, and data-driven</h2>
<p class="section-body">
All results below are generated by <code>oxo-bench</code>, the standalone benchmarking
crate included in this repository. Every table is backed by a static CSV file in
<code>docs/</code> — re-run <code>cargo run -p oxo-bench -- export-csv</code> to
refresh with your own hardware timings.
</p>
<div class="bench-tabs">
<button class="bench-tab active" data-panel="wf">⚙️ Workflow engine</button>
<button class="bench-tab" data-panel="sim">🧬 Simulation scenarios</button>
<button class="bench-tab" data-panel="eval">🤖 LLM eval tasks</button>
</div>
<div class="bench-panel active" id="bench-panel-wf">
<div class="bench-table-wrap">
<table class="bench-table" id="wf-table">
<thead>
<tr>
<th>Workflow</th>
<th class="bench-num">Tasks (expanded)</th>
<th class="bench-num">Parse (µs)</th>
<th class="bench-num">Expand (µs)</th>
<th>Cycle-free?</th>
</tr>
</thead>
<tbody id="wf-tbody">
<tr><td colspan="5" class="bench-loading">Loading bench_workflow.csv…</td></tr>
</tbody>
</table>
</div>
<p class="bench-note">
Parse and expand timings are averaged over 500 runs on a single-core.
Source: <code>docs/bench_workflow.csv</code> · generated by
<code>cargo run -p oxo-bench -- export-csv</code>
</p>
</div>
<div class="bench-panel" id="bench-panel-sim">
<div class="bench-table-wrap">
<table class="bench-table" id="sim-table">
<thead>
<tr>
<th>Scenario ID</th>
<th>Assay</th>
<th class="bench-num">Samples</th>
<th class="bench-num">Read length (bp)</th>
<th class="bench-num">Reads / sample</th>
<th class="bench-num">Error rate</th>
<th class="bench-num">Total reads</th>
</tr>
</thead>
<tbody id="sim-tbody">
<tr><td colspan="7" class="bench-loading">Loading bench_scenarios.csv…</td></tr>
</tbody>
</table>
</div>
<p class="bench-note">
All reads are generated deterministically with a fixed seed — re-running
<code>oxo-bench simulate</code> always produces byte-identical FASTQ files.
Source: <code>docs/bench_scenarios.csv</code>
</p>
</div>
<div class="bench-panel" id="bench-panel-eval">
<div class="bench-table-wrap">
<table class="bench-table" id="eval-table">
<colgroup>
<col />
<col />
<col />
<col />
</colgroup>
<thead>
<tr>
<th>Category</th>
<th>Tool</th>
<th class="bench-task-desc">Task description</th>
<th class="bench-patterns">Required patterns</th>
</tr>
</thead>
<tbody id="eval-tbody">
<tr><td colspan="4" class="bench-loading">Loading bench_eval_tasks.csv…</td></tr>
</tbody>
</table>
</div>
<p class="bench-note">
These 12 tasks form the canonical evaluation suite used to measure model
accuracy, format-validity rate, and self-consistency. Run
<code>oxo-bench eval-models --list</code> to explore the full suite.
Source: <code>docs/bench_eval_tasks.csv</code>
</p>
</div>
</section>
<hr class="divider" />
<section id="install">
<div class="section-label">// install</div>
<h2 class="section-title">Get started in 60 seconds</h2>
<div class="code-block">
<div class="code-block-header">
<span>Install from crates.io (recommended)</span>
<button class="copy-btn" data-copy="cargo install oxo-call">copy</button>
</div>
<pre><span class="c"># Install the latest release from crates.io</span>
cargo install oxo-call</pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Install from GitHub Releases (pre-built binaries)</span>
<button class="copy-btn" data-copy="curl -LO https://github.com/Traitome/oxo-call/releases/latest">copy</button>
</div>
<pre><span class="c"># Download pre-built binary (Linux x86_64 example)</span>
curl -LO https://github.com/Traitome/oxo-call/releases/latest/download/oxo-call-<span class="s">VERSION</span>-x86_64-unknown-linux-gnu.tar.gz
tar xzf oxo-call-*-x86_64-unknown-linux-gnu.tar.gz
sudo mv oxo-call /usr/local/bin/
<span class="c"># Available for: Linux (x86_64/aarch64), macOS (Intel/Apple Silicon), Windows, WASM</span></pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Install from source (git clone)</span>
<button class="copy-btn" data-copy="git clone https://github.com/Traitome/oxo-call && cd oxo-call && cargo install --path .">copy</button>
</div>
<pre><span class="c"># Clone and build from source (latest development version)</span>
cargo install --git https://github.com/Traitome/oxo-call oxo-call</pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Configure your LLM token</span>
<button class="copy-btn" data-copy="oxo-call config set llm.api_token YOUR_TOKEN">copy</button>
</div>
<pre><span class="c"># GitHub Copilot (default — free for Copilot subscribers)</span>
oxo-call config set llm.api_token YOUR_GITHUB_TOKEN
<span class="c"># OpenAI</span>
oxo-call config set llm.provider openai
oxo-call config set llm.api_token sk-...
<span class="c"># Local Ollama (no token needed)</span>
oxo-call config set llm.provider ollama
oxo-call config set llm.model llama3.2</pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Your first command</span>
<button class="copy-btn" data-copy='oxo-call dry-run samtools "sort input.bam by coordinate and output to sorted.bam"'>copy</button>
</div>
<pre><span class="c"># Preview — no execution</span>
oxo-call dry-run samtools <span class="s">"sort input.bam by coordinate and output to sorted.bam"</span>
<span class="c"># Execute immediately</span>
oxo-call run bwa <span class="s">"align reads.fastq to reference.fa using 8 threads, output SAM"</span>
<span class="c"># Confirm before running</span>
oxo-call run --ask bcftools <span class="s">"call variants from my.bam against ref.fa"</span></pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Variable interpolation & batch execution</span>
<button class="copy-btn" data-copy='oxo-call run --var SAMPLE=NA12878 samtools "index {SAMPLE}.bam"'>copy</button>
</div>
<pre><span class="c"># Variable substitution with --var</span>
oxo-call run --var SAMPLE=NA12878 samtools <span class="s">"index {SAMPLE}.bam"</span>
<span class="c"># → samtools index NA12878.bam</span>
<span class="c"># Batch processing with {item} placeholder</span>
oxo-call run samtools <span class="s">"flagstat {item}"</span> \
--input-items s1.bam,s2.bam,s3.bam --jobs 4
<span class="c"># Process files from a list with path placeholders</span>
<span class="c"># {stem} = filename without extension, {ext} = extension</span>
oxo-call run samtools <span class="s">"sort {item} -o {stem}.sorted.{ext}"</span> \
--input-list bam_files.txt --jobs 8
<span class="c"># Combine variables and batch input</span>
oxo-call run bwa <span class="s">"mem -t {THREADS} {REF} {item} > {stem}.sam"</span> \
--var THREADS=16 --var REF=hg38.fa \
--input-list samples.txt --jobs 4</pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>WASI binary (requires wasmtime)</span>
<button class="copy-btn" data-copy="wasmtime oxo-call.wasm -- dry-run samtools "sort input.bam by coordinate"">copy</button>
</div>
<pre><span class="c"># Download the .wasm binary from the GitHub Releases page, then:</span>
wasmtime oxo-call.wasm -- dry-run samtools <span class="s">"sort input.bam by coordinate"</span></pre>
</div>
<div class="code-block">
<div class="code-block-header">
<span>Quick test license (copy & paste to get started)</span>
<button class="copy-btn" data-copy='{
"schema": "oxo-call-license-v1",
"license_id": "6548e181-e352-402a-ab72-4da51f49e7b5",
"issued_to_org": "Public Academic Test License (any academic user)",
"license_type": "academic",
"scope": "org",
"perpetual": true,
"issued_at": "2026-03-12",
"signature": "duKJcISYPdyZkw1PbyVil5zTjvLhAYsmbzRpH0n6eRYJET90p1b0rYiHO0cJ7IGR6NLEJWqkY1wBXUkfvUvECw=="
}'>copy license JSON</button>
</div>
<pre><span class="c"># Step 1: Copy this JSON and save it as license.oxo.json</span>
{
"schema": "oxo-call-license-v1",
"license_id": "6548e181-e352-402a-ab72-4da51f49e7b5",
"issued_to_org": "Public Academic Test License (any academic user)",
"license_type": "academic",
"scope": "org",
"perpetual": true,
"issued_at": "2026-03-12",
"signature": "duKJcISYPdyZkw1PbyVil5zTjvLhAYsmbzRpH0n6eRYJET90p1b0rYiHO0cJ7IGR6NLEJWqkY1wBXUkfvUvECw=="
}
<span class="c"># Step 2: Move the file to the config directory</span>
<span class="c"># Linux:</span>
mkdir -p ~/.config/oxo-call && mv license.oxo.json ~/.config/oxo-call/
<span class="c"># macOS:</span>
mkdir -p ~/Library/Application\ Support/io.traitome.oxo-call && mv license.oxo.json ~/Library/Application\ Support/io.traitome.oxo-call/
<span class="c"># Windows (PowerShell):</span>
New-Item -ItemType Directory -Force -Path $env:APPDATA\oxo-call; Move-Item license.oxo.json $env:APPDATA\oxo-call\
<span class="c"># Step 3: Verify the license works</span>
oxo-call license verify
<span class="c"># Step 4: Try your first command</span>
oxo-call dry-run samtools <span class="s">"sort input.bam by coordinate"</span></pre>
</div>
<p class="section-body">
<strong>Quick test license is for evaluation only.</strong>
It lets you try oxo-call immediately without any setup.
For continued use, academic users should request a free formal license,
and commercial users should contact <a href="mailto:w_shixiang@163.com">w_shixiang@163.com</a>
to purchase a license (USD 200 per organization).
</p>
<div class="paypal-section" id="paypal-section">
<div class="paypal-header" onclick="togglePaypal()">
<div class="paypal-title">
<span class="paypal-icon">💳</span>
<span>Commercial License Payment</span>
</div>
<span class="paypal-toggle">▼</span>
</div>
<div class="paypal-content">
<div class="paypal-inner">
<div class="paypal-qr">
<img src="paypal.png" alt="PayPal QR Code" />
</div>
<div class="paypal-info">
<div class="price">USD $200</div>
<h4>Per-organization Commercial License</h4>
<p>One-time payment, perpetual license covering all employees and contractors within your organization.</p>
<div class="paypal-note">
<strong>⚠️ Important:</strong> Please include your <strong>organization name</strong> and <strong>email address</strong> in the payment note.
The formal license file will be sent to your email within one week after payment confirmation.
</div>
</div>
</div>
</div>
</div>
</section>
<section id="community">
<div class="section-label">// community & feedback</div>
<div class="community-banner">
<div>
<h2>oxo-call is built by users, for users 🚀</h2>
<p>
This is an <strong>actively developed, feedback-driven project</strong>.
Your bug reports, feature requests, and real-world use cases directly shape
what gets built next. Whether you're a student running your first RNA-seq
pipeline or a bioinformatics core facility supporting dozens of assays —
your experience matters. Try it, break it, and tell us what happened!
</p>
<div class="community-actions">
<a href="https://github.com/Traitome/oxo-call/issues" class="btn btn-secondary btn-sm" target="_blank" rel="noopener">
Browse Issues
</a>
<a href="documentation/development/contributing.html" class="btn btn-secondary btn-sm">
Contributing Guide
</a>
</div>
</div>
<div class="community-links">
<a class="community-link" href="https://github.com/Traitome/oxo-call/issues/new?template=bug_report.md" target="_blank" rel="noopener">
<span class="emoji">🐛</span> Report a bug
</a>
<a class="community-link" href="https://github.com/Traitome/oxo-call/issues/new?template=feature_request.md" target="_blank" rel="noopener">
<span class="emoji">💡</span> Request a feature
</a>
<a class="community-link" href="https://github.com/Traitome/oxo-call/issues/new?template=skill_request.md" target="_blank" rel="noopener">
<span class="emoji">🎯</span> Request a skill
</a>
<a class="community-link" href="https://github.com/Traitome/oxo-call" target="_blank" rel="noopener">
<span class="emoji">⭐</span> Star on GitHub
</a>
</div>
</div>
</section>
<hr class="divider" />
<footer>
<p>
<strong>oxo-call</strong> is dual-licensed: free for academic use, commercial license <strong>USD 200</strong>/org.
Contact <a href="mailto:w_shixiang@163.com">w_shixiang@163.com</a> for commercial licensing.
·
<a href="https://github.com/Traitome/oxo-call" target="_blank" rel="noopener">GitHub</a>
·
<a href="https://crates.io/crates/oxo-call" target="_blank" rel="noopener">crates.io</a>
·
<a href="https://github.com/Traitome/oxo-call/blob/main/LICENSE-ACADEMIC" target="_blank" rel="noopener">License</a>
</p>
</footer>
<script>
(function () {
const lines = [
{
cmd: 'oxo-call dry-run samtools "sort input.bam by coordinate → sorted.bam"',
out: [
' ⠋ Fetching samtools documentation…',
' ⠙ Loading built-in skill: samtools',
' ✔ Skill loaded (v1.0)',
' ⠸ Asking LLM backend…',
'',
' EXPLANATION: samtools sort takes an input BAM and writes',
' coordinate-sorted output. -o sets the output path.',
'',
' $ samtools sort -o sorted.bam input.bam',
'',
],
},
{
cmd: 'oxo-call run bwa "align paired reads R1.fastq R2.fastq to hg38.fa, 16 threads"',
out: [
' ⠋ Fetching bwa documentation…',
' ⠙ Loading built-in skill: bwa',
' ✔ Skill loaded (v1.0)',
' ⠸ Asking LLM backend…',
'',
' EXPLANATION: bwa mem handles paired-end reads with -t for threads.',
' Redirect stdout to SAM output file.',
'',
' $ bwa mem -t 16 hg38.fa R1.fastq R2.fastq > aligned.sam',
'',
],
},
{
cmd: 'oxo-call run --var SAMPLE=NA12878 samtools "index {SAMPLE}.bam"',
out: [
' ⠋ Fetching samtools documentation…',
' ⠙ Loading built-in skill: samtools',
' ✔ Skill loaded (v1.0)',
' ⠸ Substituting {SAMPLE} → NA12878…',
' ⠸ Asking LLM backend…',
'',
' EXPLANATION: samtools index creates a .bai index file for fast',
' random access. The .bam extension is preserved.',
'',
' $ samtools index NA12878.bam',
'',
],
},
{
cmd: 'oxo-call run samtools "flagstat {item}" --input-items s1.bam,s2.bam --jobs 2',
out: [
' ⠋ Fetching samtools documentation…',
' ⠙ Loading built-in skill: samtools',
' ✔ Skill loaded (v1.0)',
' ⠸ Querying LLM for command template…',
'',
' Command template: samtools flagstat {item}',
'',
' [1/2] $ samtools flagstat s1.bam',
' ✔ success (exit 0)',
' [2/2] $ samtools flagstat s2.bam',
' ✔ success (exit 0)',
'',
],
},
];
let lineIdx = 0;
const typingEl = document.getElementById('hero-typing');
const cursorEl = document.getElementById('hero-cursor');
const bodyEl = document.getElementById('hero-term-body');
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
async function typeString(el, str, speed = 28) {
for (const ch of str) {
el.textContent += ch;
await sleep(speed + Math.random() * 20);
}
}
async function runLine(entry) {
typingEl.textContent = '';
cursorEl.style.display = 'inline-block';
await sleep(600);
await typeString(typingEl, entry.cmd, 22);
cursorEl.style.display = 'none';
await sleep(300);
for (const o of entry.out) {
const span = document.createElement('span');
span.className = 'term-line';
if (o.includes('$')) {
span.innerHTML = o.replace(/\$ (.*)/, ' <span class="prompt">$</span> <span class="success">$1</span>');
} else if (o.includes('✔')) {
span.innerHTML = `<span class="success">${escHtml(o)}</span>`;
} else if (o.includes('EXPLANATION')) {
span.innerHTML = `<span class="warn">${escHtml(o)}</span>`;
} else {
span.innerHTML = `<span class="output">${escHtml(o)}</span>`;
}
bodyEl.appendChild(span);
await sleep(80);
}
await sleep(2200);
while (bodyEl.children.length > 1) bodyEl.removeChild(bodyEl.lastChild);
}
function escHtml(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
async function loop() {
while (true) {
await runLine(lines[lineIdx % lines.length]);
lineIdx++;
}
}
loop();
})();
(function () {
const examples = [
{
tool: 'samtools',
task: 'sort input.bam by coordinate and output to sorted.bam',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching samtools documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: samtools' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: samtools sort reorders reads by leftmost coordinate.' },
{ t: 'warn', s: ' -o sets the output path. No -n flag for name sort.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ samtools sort -o sorted.bam input.bam' },
],
},
{
tool: 'bwa',
task: 'align paired reads R1.fastq R2.fastq to hg38.fa using 16 threads, output SAM',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching bwa documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: bwa' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: bwa mem is recommended for reads >70 bp.' },
{ t: 'warn', s: ' -t sets the number of threads.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ bwa mem -t 16 hg38.fa R1.fastq R2.fastq > aligned.sam' },
],
},
{
tool: 'bcftools',
task: 'call variants from my.bam against ref.fa and output to variants.vcf',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching bcftools documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: bcftools' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: bcftools mpileup + call pipeline. -Ou pipes BCF' },
{ t: 'warn', s: ' uncompressed. -mv calls multiallelic variants.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ bcftools mpileup -f ref.fa my.bam | bcftools call -mv -o variants.vcf' },
],
},
{
tool: 'fastp',
task: 'trim adapters from paired-end reads R1.fastq R2.fastq and output trimmed reads',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching fastp documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: fastp' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: fastp auto-detects adapters. -i/-I for input pairs,' },
{ t: 'warn', s: ' -o/-O for output. -j/-h for JSON/HTML reports.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ fastp -i R1.fastq -I R2.fastq -o R1_trimmed.fastq -O R2_trimmed.fastq -j report.json -h report.html' },
],
},
{
tool: 'minimap2',
task: 'align long reads ONT.fastq to reference.fa and output PAF',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching minimap2 documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: minimap2' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: -x map-ont selects the ONT long-read preset.' },
{ t: 'warn', s: ' Without -a the default output format is PAF.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ minimap2 -x map-ont reference.fa ONT.fastq > aligned.paf' },
],
},
{
tool: 'seqkit',
task: 'get basic stats on sample.fastq.gz',
subcmd:'dry-run',
steps: [
{ t: 'output', s: ' ⠋ Fetching seqkit documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: seqkit' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: seqkit stats reports read counts, lengths, and GC%.' },
{ t: 'warn', s: ' -a reports all extended statistics.' },
{ t: 'blank', s: '' },
{ t: 'cmd', s: ' $ seqkit stats -a sample.fastq.gz' },
],
},
{
tool: 'samtools',
task: 'index {item} and output to {stem}.bai',
subcmd:'dry-run',
flags: '--input-items sample1.bam,sample2.bam --jobs 2',
steps: [
{ t: 'output', s: ' ⠋ Fetching samtools documentation…' },
{ t: 'output', s: ' ⠙ Loading built-in skill: samtools' },
{ t: 'success',s: ' ✔ Skill loaded' },
{ t: 'output', s: ' ⠸ Querying LLM for command template…' },
{ t: 'blank', s: '' },
{ t: 'warn', s: ' EXPLANATION: Template uses {item} for input, {stem} for base name.' },
{ t: 'warn', s: ' --jobs 2 runs up to 2 parallel indexing jobs.' },
{ t: 'blank', s: '' },
{ t: 'success',s: ' Command template:' },
{ t: 'cmd', s: ' $ samtools index {item}' },
{ t: 'blank', s: '' },
{ t: 'success',s: ' Expanded commands (2 jobs parallel):' },
{ t: 'cmd', s: ' [1/2] $ samtools index sample1.bam' },
{ t: 'cmd', s: ' [2/2] $ samtools index sample2.bam' },
],
},
];
const demoBody = document.getElementById('demo-body');
const demoTitle = document.getElementById('demo-term-title');
function escHtml(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
let running = false;
async function renderExample(idx) {
if (running) return;
running = true;
const ex = examples[idx];
demoTitle.textContent = ex.flags
? `oxo-call ${ex.subcmd} ${ex.tool} ${ex.flags}`
: `oxo-call ${ex.subcmd} ${ex.tool}`;
demoBody.innerHTML = '';
const promptLine = document.createElement('div');
promptLine.className = 'term-line';
let promptHtml = `<span class="prompt">$ </span>` +
`<span class="tool">oxo-call</span>` +
` <span class="flag">${ex.subcmd}</span>`;
if (ex.flags) {
promptHtml += ` <span class="flag">${escHtml(ex.flags)}</span>`;
}
promptHtml += ` <span class="tool">${escHtml(ex.tool)}</span>` +
` <span class="output">"${escHtml(ex.task)}"</span>`;
promptLine.innerHTML = promptHtml;
demoBody.appendChild(promptLine);
await sleep(400);
for (const step of ex.steps) {
await sleep(120);
const line = document.createElement('div');
line.className = 'term-line';
if (step.t === 'cmd') {
line.innerHTML = step.s.replace(
/\$ (.*)/,
'<span class="prompt"> $</span> <span class="success">$1</span>'
);
} else if (step.t === 'success') {
line.innerHTML = `<span class="success">${escHtml(step.s)}</span>`;
} else if (step.t === 'warn') {
line.innerHTML = `<span class="warn">${escHtml(step.s)}</span>`;
} else {
line.innerHTML = `<span class="output">${escHtml(step.s)}</span>`;
}
demoBody.appendChild(line);
}
running = false;
}
document.querySelectorAll('.demo-example').forEach(el => {
el.addEventListener('click', () => {
document.querySelectorAll('.demo-example').forEach(e => e.classList.remove('active'));
el.classList.add('active');
renderExample(parseInt(el.dataset.idx, 10));
});
});
renderExample(0);
})();
document.querySelectorAll('.copy-btn').forEach(btn => {
btn.addEventListener('click', async () => {
const text = btn.dataset.copy;
try {
await navigator.clipboard.writeText(text);
btn.textContent = 'copied!';
btn.classList.add('copied');
setTimeout(() => {
btn.textContent = 'copy';
btn.classList.remove('copied');
}, 1800);
} catch (_) {}
});
});
(function () {
function parseCsv(text) {
const rows = [];
const lines = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
for (const line of lines) {
if (!line.trim()) continue;
const fields = [];
let i = 0;
while (i < line.length) {
if (line[i] === '"') {
i++; let val = '';
while (i < line.length) {
if (line[i] === '"' && line[i + 1] === '"') { val += '"'; i += 2; }
else if (line[i] === '"') { i++; break; }
else { val += line[i++]; }
}
fields.push(val);
if (line[i] === ',') i++;
} else {
let j = line.indexOf(',', i);
if (j === -1) j = line.length;
fields.push(line.slice(i, j));
i = j + 1;
}
}
rows.push(fields);
}
return rows;
}
function escH(s) {
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
}
fetch('bench_workflow.csv')
.then(r => r.text())
.then(txt => {
const rows = parseCsv(txt);
const tbody = document.getElementById('wf-tbody');
tbody.innerHTML = '';
rows.slice(1).forEach(([wf, tasks, parseUs, expandUs, cycleFree]) => {
const ok = cycleFree === 'true';
tbody.insertAdjacentHTML('beforeend', `
<tr>
<td><span class="tool">${escH(wf)}</span></td>
<td class="bench-num">${escH(tasks)}</td>
<td class="bench-num">${escH(parseUs)}</td>
<td class="bench-num">${escH(expandUs)}</td>
<td><span class="${ok ? 'bench-ok' : 'warn'}">${ok ? '✓ yes' : '⚠ cycle!'}</span></td>
</tr>`);
});
})
.catch(() => {
document.getElementById('wf-tbody').innerHTML =
'<tr><td colspan="5" class="bench-loading">Could not load bench_workflow.csv</td></tr>';
});
fetch('bench_scenarios.csv')
.then(r => r.text())
.then(txt => {
const rows = parseCsv(txt);
const tbody = document.getElementById('sim-tbody');
tbody.innerHTML = '';
rows.slice(1).forEach(([id, assay, n, rlen, rps, err, total]) => {
const totalNum = parseInt(total, 10);
const totalFmt = totalNum >= 1_000_000
? (totalNum / 1_000_000).toFixed(1) + ' M'
: totalNum >= 1_000
? (totalNum / 1_000).toFixed(0) + ' k'
: total;
tbody.insertAdjacentHTML('beforeend', `
<tr>
<td><code>${escH(id)}</code></td>
<td><span class="bench-badge-assay">${escH(assay)}</span></td>
<td class="bench-num">${escH(n)}</td>
<td class="bench-num">${escH(rlen)}</td>
<td class="bench-num">${escH(rps)}</td>
<td class="bench-num">${escH(err)}</td>
<td class="bench-num">${escH(totalFmt)}</td>
</tr>`);
});
})
.catch(() => {
document.getElementById('sim-tbody').innerHTML =
'<tr><td colspan="7" class="bench-loading">Could not load bench_scenarios.csv</td></tr>';
});
fetch('bench_eval_tasks.csv')
.then(r => r.text())
.then(txt => {
const rows = parseCsv(txt);
const tbody = document.getElementById('eval-tbody');
tbody.innerHTML = '';
rows.slice(1).forEach(([cat, tool, task, pats]) => {
const patHtml = pats.split(';').map(p =>
`<code>${escH(p.trim())}</code>`).join(' ');
tbody.insertAdjacentHTML('beforeend', `
<tr>
<td><span class="bench-cat">${escH(cat)}</span></td>
<td><span class="tool">${escH(tool)}</span></td>
<td class="bench-task-desc">${escH(task)}</td>
<td class="bench-patterns">${patHtml}</td>
</tr>`);
});
})
.catch(() => {
document.getElementById('eval-tbody').innerHTML =
'<tr><td colspan="4" class="bench-loading">Could not load bench_eval_tasks.csv</td></tr>';
});
document.querySelectorAll('.bench-tab').forEach(tab => {
tab.addEventListener('click', () => {
document.querySelectorAll('.bench-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.bench-panel').forEach(p => p.classList.remove('active'));
tab.classList.add('active');
document.getElementById('bench-panel-' + tab.dataset.panel).classList.add('active');
});
});
})();
(function () {
const allTools = [
{ name: 'samtools', desc: 'SAM/BAM/CRAM manipulation', icon: '🧬' },
{ name: 'bwa', desc: 'Burrows-Wheeler short-read aligner', icon: '🎯' },
{ name: 'bcftools', desc: 'VCF/BCF variant calling & filtering', icon: '🧪' },
{ name: 'bedtools', desc: 'Genomic interval arithmetic', icon: '🛏️' },
{ name: 'gatk', desc: 'Genome Analysis Toolkit', icon: '🔬' },
{ name: 'minimap2', desc: 'Long-read / splice-aware aligner', icon: '📏' },
{ name: 'fastp', desc: 'Adapter trimming & QC', icon: '✂️' },
{ name: 'bowtie2', desc: 'Fast short-read aligner', icon: '🎀' },
{ name: 'seqkit', desc: 'FASTA/Q toolkit', icon: '🧰' },
{ name: 'star', desc: 'RNA-seq spliced aligner', icon: '⭐' },
{ name: 'slurm', desc: 'HPC job scheduling (sbatch, srun)', icon: '⚡' },
{ name: 'pbs', desc: 'PBS/Torque batch scheduler (qsub)', icon: '📋' },
{ name: 'kubectl', desc: 'Kubernetes cluster management', icon: '☸️' },
{ name: 'picard', desc: 'BAM manipulation & metrics', icon: '🎭' },
{ name: 'hisat2', desc: 'Splice-aware RNA-seq aligner', icon: '🧵' },
{ name: 'salmon', desc: 'Transcript quantification', icon: '🐟' },
{ name: 'featureCounts', desc: 'Read summarization', icon: '🔢' },
{ name: 'macs3', desc: 'Peak calling for ChIP-seq', icon: '🏔️' },
{ name: 'deeptools', desc: 'NGS data visualization', icon: '📊' },
{ name: 'multiqc', desc: 'Aggregate QC reports', icon: '📈' },
{ name: 'trimmomatic', desc: 'Illumina adapter trimming', icon: '✂️' },
{ name: 'kraken2', desc: 'Taxonomic classification', icon: '🐙' },
{ name: 'blast', desc: 'Sequence similarity search', icon: '💥' },
{ name: 'vcftools', desc: 'VCF manipulation & filtering', icon: '🧬' },
{ name: 'plink', desc: 'GWAS & population genetics', icon: '🔗' },
{ name: 'singularity', desc: 'Container runtime for HPC', icon: '📦' },
{ name: 'docker', desc: 'Container platform', icon: '🐳' },
{ name: 'conda', desc: 'Package & environment manager', icon: '🐍' },
{ name: 'vcflib', desc: 'VCF processing toolkit', icon: '📚' },
{ name: 'freebayes', desc: 'Bayesian variant caller', icon: '🎲' },
{ name: 'ivar', desc: 'Viral amplicon-based sequencing', icon: '🦠' },
{ name: 'lofreq', desc: 'Sensitive variant caller', icon: '🔍' },
{ name: 'mosdepth', desc: 'Fast BAM/CRAM depth calculation', icon: '📐' },
{ name: 'qualimap', desc: 'BAM QC analysis', icon: '✅' },
{ name: 'rsem', desc: 'RNA-seq quantification', icon: '📊' },
{ name: 'kallisto', desc: 'Pseudoalignment quantification', icon: '⚡' },
{ name: 'stringtie', desc: 'Transcript assembly', icon: '🧵' },
{ name: 'gffread', desc: 'GFF/GTF manipulation', icon: '📖' },
{ name: 'bedops', desc: 'High-performance BED tools', icon: '🚀' },
{ name: 'sra-toolkit', desc: 'NCBI SRA data download', icon: '⬇️' },
{ name: 'parallel', desc: 'GNU parallel execution', icon: '⚡' },
{ name: 'htop', desc: 'Interactive process viewer', icon: '📊' },
{ name: 'lsf', desc: 'IBM LSF workload scheduler', icon: '🏢' },
{ name: 'sge', desc: 'Sun Grid Engine', icon: '☀️' },
{ name: 'htcondor', desc: 'High Throughput Computing', icon: '🦅' },
];
const grid = document.getElementById('tools-grid');
if (!grid) return;
const cards = grid.querySelectorAll('.tool-card');
let visibleIndices = new Set(Array.from({length: cards.length}, (_, i) => i));
function randomHighlight() {
const idx = Math.floor(Math.random() * cards.length);
const card = cards[idx];
if (card && !card.matches(':hover')) {
card.style.transform = 'translateY(-8px) scale(1.03)';
card.style.borderColor = 'var(--accent2)';
card.style.boxShadow = '0 12px 30px rgba(63,185,80,0.25)';
setTimeout(() => {
card.style.transform = '';
card.style.borderColor = '';
card.style.boxShadow = '';
}, 800);
}
}
function waveEffect() {
cards.forEach((card, i) => {
setTimeout(() => {
if (!card.matches(':hover')) {
card.style.borderColor = 'var(--accent)';
card.style.boxShadow = '0 0 20px rgba(88,166,255,0.3)';
setTimeout(() => {
card.style.borderColor = '';
card.style.boxShadow = '';
}, 300);
}
}, i * 50);
});
}
function shuffleTools() {
const visible = Array.from(visibleIndices);
const hidden = allTools.map((_, i) => i).filter(i => !visibleIndices.has(i));
if (hidden.length === 0) return;
const numToSwap = Math.floor(Math.random() * 3) + 1;
for (let n = 0; n < numToSwap; n++) {
const outIdx = visible[Math.floor(Math.random() * visible.length)];
const inIdx = hidden[Math.floor(Math.random() * hidden.length)];
const card = cards[outIdx];
if (card && !card.matches(':hover')) {
card.style.transform = 'rotateY(90deg) scale(0.8)';
card.style.opacity = '0';
setTimeout(() => {
const iconEl = card.querySelector('.tool-icon');
const nameEl = card.querySelector('.tool-name');
const descEl = card.querySelector('.tool-desc');
if (iconEl) iconEl.textContent = allTools[inIdx].icon;
if (nameEl) nameEl.textContent = allTools[inIdx].name;
if (descEl) descEl.textContent = allTools[inIdx].desc;
card.style.transform = 'rotateY(-90deg) scale(0.8)';
setTimeout(() => {
card.style.transform = '';
card.style.opacity = '';
}, 50);
visibleIndices.delete(outIdx);
visibleIndices.add(inIdx);
}, 300);
}
}
}
setInterval(randomHighlight, 2000);
setInterval(shuffleTools, 2000);
setInterval(waveEffect, 12000);
})();
function togglePaypal() {
const section = document.getElementById('paypal-section');
section.classList.toggle('open');
}
</script>
</body>
</html>