aboutsummaryrefslogtreecommitdiff
path: root/website/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'website/index.html')
-rw-r--r--website/index.html484
1 files changed, 294 insertions, 190 deletions
diff --git a/website/index.html b/website/index.html
index 79e350fe..53ca28aa 100644
--- a/website/index.html
+++ b/website/index.html
@@ -8,7 +8,7 @@
name="description"
content="Terminal-native agent runtime and multiplexer. Run AI coding agents in real panes, detach and reattach, SSH in, see state, and orchestrate through the CLI/socket API."
/>
- <meta name="theme-color" content="#f7f3ea" />
+ <meta name="theme-color" content="#f0eee9" />
<link rel="canonical" href="https://herdr.dev/" />
<meta property="og:type" content="website" />
@@ -48,13 +48,22 @@
type="font/woff2"
crossorigin
/>
- <link rel="stylesheet" href="/css/style.css?v=19" />
+ <script>
+ (function () {
+ var saved = localStorage.getItem("herdr-palette");
+ var system = window.matchMedia("(prefers-color-scheme: dark)").matches
+ ? "tokyo-night"
+ : "tokyo-night-day";
+ document.documentElement.setAttribute("data-palette", saved || system);
+ })();
+ </script>
+ <link rel="stylesheet" href="/css/style.css?v=20" />
</head>
<body>
<header class="site-header">
<nav class="nav" aria-label="Primary navigation">
<a class="brand" href="/" aria-label="Herdr home">
- <img class="brand-logo" src="/assets/logo.svg" alt="" />
+ <span class="brand-logo" aria-hidden="true"></span>
<span>herdr</span>
</a>
<div class="nav-links">
@@ -64,14 +73,16 @@
<a href="/docs/socket-api/">API</a>
<a href="https://github.com/ogulcancelik/herdr">GitHub</a>
</div>
- <a class="nav-cta" href="/docs/install/">Install</a>
+ <div class="nav-tools">
+ <a class="nav-cta" href="/docs/install/">Install</a>
+ </div>
</nav>
</header>
<main>
<section class="hero" id="hero">
- <div class="hero-pasture" aria-hidden="true"></div>
- <div class="hero-copy">
+ <div class="hero-left">
+ <div class="hero-copy">
<p class="eyebrow">
<span class="status-dot dot-done"></span>
Terminal-native agent runtime
@@ -133,7 +144,9 @@
binary · no Electron
</p>
</div>
+ </div>
+ <div class="hero-right">
<figure class="hero-product-shot">
<div
class="herdr-ui-mock"
@@ -158,7 +171,7 @@
<div class="mock-sidebar-row"><span>new</span><span>menu</span></div>
<div class="mock-agent-title"><span>agents</span><span>all</span></div>
<div class="mock-agent"><span>✓</span><div><strong>doc</strong><small>idle · pi</small></div></div>
- <div class="mock-agent working"><span>⠴</span><div><strong>custom-row</strong><small>working · pi</small></div></div>
+ <div class="mock-agent working"><span class="braille-spinner"></span><div><strong>custom-row</strong><small>working · pi</small></div></div>
<div class="mock-agent blocked"><span>◉</span><div><strong>llm-proxy</strong><small>blocked · claude</small></div></div>
<div class="mock-agent done"><span>●</span><div><strong>qmp</strong><small>done · codex</small></div></div>
</aside>
@@ -202,20 +215,7 @@
The whole herd in one terminal.
</figcaption>
</figure>
- </section>
-
- <section class="demo-section" aria-label="Herdr demo">
- <video
- class="demo-video"
- autoplay
- muted
- loop
- playsinline
- preload="auto"
- poster="/assets/hero-session.png"
- >
- <source src="/assets/demo-v2.mp4" type="video/mp4" />
- </video>
+ </div>
</section>
<section class="logo-cloud" aria-labelledby="logo-cloud-title">
@@ -425,12 +425,33 @@
<li>Stay keyboard-first, or disable mouse input entirely.</li>
</ul>
</div>
- <figure class="screenshot-card">
- <img
- src="/assets/terminal-panes.png"
- alt="Herdr showing real terminal panes side by side"
- loading="lazy"
- />
+ <figure class="feature-mock" role="img" aria-label="Herdr showing split terminal panes">
+ <div class="mock-panes feature-mock-panes">
+ <div class="mock-pane focused">
+ <div class="mock-prompt"><span>~/Projects/herdr</span> <em>master</em></div>
+ <div><b>❯</b> <span class="cmd">just</span> <span class="str">test</span></div>
+ <div class="dim">cargo nextest run</div>
+ <div><span class="time">02:14:22</span> <span class="green">PASS</span> app::state::tests</div>
+ <div><span class="time">02:14:23</span> <span class="green">PASS</span> platform::pty::tests</div>
+ <div><span class="time">02:14:24</span> <span class="green">PASS</span> protocol::wire::tests</div>
+ <br />
+ <div><span class="green">3 passed</span> · 0 failed · 0.8s</div>
+ <div class="mock-prompt"><span>~/Projects/herdr</span> <em>master</em></div>
+ <div><b>❯</b> <span class="cursor"></span></div>
+ </div>
+ <div class="mock-pane">
+ <div class="mock-prompt"><span>~/Projects/herdr</span> <em>master</em></div>
+ <div><b>❯</b> <span class="cmd">git</span> <span class="str">status</span></div>
+ <div class="dim">On branch master</div>
+ <div>Your branch is up to date.</div>
+ <br />
+ <div class="dim">Changes not staged:</div>
+ <div><span class="red">M</span> src/app/state.rs</div>
+ <div><span class="green">??</span> docs/next/</div>
+ <br />
+ <div class="dim">2 files changed, 14 insertions</div>
+ </div>
+ </div>
</figure>
</section>
@@ -588,30 +609,52 @@ $ herdr</code></pre>
<h2>Keep the herd in sight.</h2>
</div>
<div class="awareness-grid">
- <article class="awareness-card">
- <img
- src="/assets/sidebar-workspaces-v2.png"
- alt="Herdr workspace sidebar state"
- loading="lazy"
- />
- <h3>Workspace rollups</h3>
- <p>
- Each workspace rolls up to its most urgent agent
- state, so the whole session is scannable.
- </p>
- </article>
- <article class="awareness-card">
- <img
- src="/assets/sidebar-agents-v2.png"
- alt="Herdr agent sidebar state"
- loading="lazy"
- />
- <h3>Agent list</h3>
- <p>
- See which agents are blocked, working, done, idle, or
- unknown without opening every pane.
- </p>
- </article>
+ <article class="awareness-card">
+ <figure class="awareness-mock" role="img" aria-label="Herdr workspace sidebar showing state rollups">
+ <div class="mock-sidebar">
+ <div class="mock-sidebar-title">spaces</div>
+ <div class="mock-space active">
+ <span class="mock-dot dot-done"></span>
+ <div><strong>herdr</strong><small>master</small></div>
+ </div>
+ <div class="mock-space">
+ <span class="mock-dot dot-working"></span>
+ <div><strong>llm-proxy</strong><small>master</small></div>
+ </div>
+ <div class="mock-space">
+ <span class="mock-dot dot-blocked"></span>
+ <div><strong>docs-site</strong><small>docs/palette</small></div>
+ </div>
+ <div class="mock-space">
+ <span class="mock-dot dot-idle"></span>
+ <div><strong>qmp</strong><small>autoresearch/…</small></div>
+ </div>
+ <div class="mock-sidebar-spacer"></div>
+ </div>
+ </figure>
+ <h3>Workspace rollups</h3>
+ <p>
+ Each workspace rolls up to its most urgent agent
+ state, so the whole session is scannable.
+ </p>
+ </article>
+ <article class="awareness-card">
+ <figure class="awareness-mock" role="img" aria-label="Herdr agent list showing states">
+ <div class="mock-sidebar">
+ <div class="mock-agent-title"><span>agents</span><span>all</span></div>
+ <div class="mock-agent"><span>✓</span><div><strong>doc</strong><small>idle · pi</small></div></div>
+ <div class="mock-agent working"><span class="braille-spinner"></span><div><strong>custom-row</strong><small>working · pi</small></div></div>
+ <div class="mock-agent blocked"><span>◉</span><div><strong>llm-proxy</strong><small>blocked · claude</small></div></div>
+ <div class="mock-agent done"><span>●</span><div><strong>qmp</strong><small>done · codex</small></div></div>
+ <div class="mock-sidebar-spacer"></div>
+ </div>
+ </figure>
+ <h3>Agent list</h3>
+ <p>
+ See which agents are blocked, working, done, idle, or
+ unknown without opening every pane.
+ </p>
+ </article>
</div>
<div class="state-legend">
<span><i class="status-dot dot-blocked"></i>blocked</span>
@@ -627,15 +670,21 @@ $ herdr</code></pre>
<p class="section-kicker">Integrations</p>
<h2>Bring your existing agents into the herd.</h2>
</div>
- <div class="integration-grid">
- <span>Pi</span>
- <span>Claude Code</span>
- <span>Codex</span>
- <span>OpenCode</span>
- <span>Droid</span>
- <span>Amp</span>
- <span>Grok CLI</span>
- <span>Gemini CLI</span>
+ <div class="agent-grid" aria-label="Supported agents">
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/pi.svg')"></span><span>Pi</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/claude.svg')"></span><span>Claude Code</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/codex-mask.svg')"></span><span>Codex</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/droid.png')"></span><span>Droid</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/amp.svg')"></span><span>Amp</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/opencode.svg')"></span><span>OpenCode</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/grok.svg')"></span><span>Grok CLI</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/hermes.svg')"></span><span>Hermes</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/cursor.svg')"></span><span>Cursor</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/antigravity.svg')"></span><span>Antigravity</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/kimi.svg')"></span><span>Kimi</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/kiro-mask.svg')"></span><span>Kiro</span></div>
+ <div class="agent-card"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/github-copilot.svg')"></span><span>Copilot</span></div>
+ <div class="agent-card agent-more"><span class="agent-icon" style="--agent-icon: url('/assets/agent-icons/herdr-mask.svg')"></span><span>more soon</span></div>
</div>
<p class="integration-note">
Any terminal agent works in Herdr. Use the Herdr API to add
@@ -665,7 +714,7 @@ $ herdr</code></pre>
<footer class="footer">
<a class="brand" href="/" aria-label="Herdr home">
- <img class="brand-logo" src="/assets/logo.svg" alt="" />
+ <span class="brand-logo" aria-hidden="true"></span>
<span>herdr</span>
</a>
<div>
@@ -686,8 +735,176 @@ $ herdr</code></pre>
<button type="button" id="copy-logo-url">Copy SVG URL</button>
</div>
+ <div class="theme-hint" id="theme-hint" title="Press / or t to switch theme">
+ <span class="theme-hint-dot"></span>
+ <span class="theme-hint-label" id="theme-hint-label">light</span>
+ <span class="theme-hint-key">[/]</span>
+ </div>
+
+ <div class="theme-overlay" id="theme-overlay" hidden>
+ <div class="theme-overlay-panel" role="dialog" aria-label="Theme switcher" aria-modal="true">
+ <div class="theme-overlay-title">settings</div>
+ <div class="theme-overlay-tabs">
+ <span class="active">theme</span>
+ </div>
+ <div class="theme-overlay-list" id="theme-overlay-list" role="listbox" aria-label="Themes">
+ <div class="theme-sep"><span>dark</span></div>
+ <button type="button" role="option" data-value="catppuccin">catppuccin</button>
+ <button type="button" role="option" data-value="terminal">terminal</button>
+ <button type="button" role="option" data-value="tokyo-night">tokyo night</button>
+ <button type="button" role="option" data-value="dracula">dracula</button>
+ <button type="button" role="option" data-value="nord">nord</button>
+ <button type="button" role="option" data-value="gruvbox">gruvbox</button>
+ <button type="button" role="option" data-value="one-dark">one dark</button>
+ <button type="button" role="option" data-value="solarized">solarized</button>
+ <button type="button" role="option" data-value="kanagawa">kanagawa</button>
+ <button type="button" role="option" data-value="rose-pine">rose pine</button>
+ <button type="button" role="option" data-value="vesper">vesper</button>
+ <div class="theme-sep"><span>light</span></div>
+ <button type="button" role="option" data-value="catppuccin-latte">catppuccin latte</button>
+ <button type="button" role="option" data-value="tokyo-night-day">tokyo day</button>
+ <button type="button" role="option" data-value="gruvbox-light">gruvbox light</button>
+ <button type="button" role="option" data-value="one-light">one light</button>
+ <button type="button" role="option" data-value="solarized-light">solarized light</button>
+ <button type="button" role="option" data-value="kanagawa-lotus">kanagawa lotus</button>
+ <button type="button" role="option" data-value="rose-pine-dawn">rose pine dawn</button>
+ </div>
+ <div class="theme-overlay-footer">
+ <span class="theme-overlay-hints"><span class="key">↑↓</span> select</span>
+ <span class="theme-overlay-actions"><span class="theme-apply-btn">↵ apply</span><button class="theme-close-btn" type="button" id="theme-close-btn">esc close</button></span>
+ </div>
+ </div>
+ </div>
+
<script>
(function () {
+ var overlay = document.getElementById("theme-overlay");
+ var list = document.getElementById("theme-overlay-list");
+ var hintLabel = document.getElementById("theme-hint-label");
+ if (!overlay || !list) return;
+
+ var options = Array.prototype.slice.call(list.querySelectorAll("[role='option']"));
+ var media = window.matchMedia("(prefers-color-scheme: dark)");
+ var saved = localStorage.getItem("herdr-palette") || "";
+ var committed = saved || defaultPalette();
+
+ function defaultPalette() {
+ return media.matches ? "tokyo-night" : "tokyo-night-day";
+ }
+
+ function setPalette(value) {
+ document.documentElement.setAttribute("data-palette", value || defaultPalette());
+ }
+
+ function updateUI(value) {
+ var activeValue = value || defaultPalette();
+ options.forEach(function (opt) {
+ var selected = opt.dataset.value === activeValue;
+ opt.setAttribute("aria-selected", String(selected));
+ });
+ var active = options.find(function (o) { return o.dataset.value === activeValue; });
+ if (hintLabel && active) hintLabel.textContent = active.textContent.trim();
+ }
+
+ function openOverlay() {
+ overlay.hidden = false;
+ document.body.style.overflow = "hidden";
+ committed = localStorage.getItem("herdr-palette") || defaultPalette();
+ updateUI(committed);
+ var active = list.querySelector("[aria-selected='true']") || options[0];
+ if (active) active.focus();
+ }
+
+ function closeOverlay() {
+ overlay.hidden = true;
+ document.body.style.overflow = "";
+ }
+
+ function toggleOverlay() {
+ if (overlay.hidden) openOverlay();
+ else closeOverlay();
+ }
+
+ function preview(index) {
+ if (index < 0 || index >= options.length) return;
+ setPalette(options[index].dataset.value);
+ updateUI(options[index].dataset.value);
+ options[index].focus();
+ }
+
+ function commit(value) {
+ setPalette(value);
+ localStorage.setItem("herdr-palette", value);
+ updateUI(value);
+ closeOverlay();
+ }
+
+ function revert() {
+ setPalette(committed);
+ updateUI(committed);
+ closeOverlay();
+ }
+
+ media.addEventListener("change", function () {
+ if (!localStorage.getItem("herdr-palette")) {
+ setPalette("");
+ updateUI("");
+ }
+ });
+
+ options.forEach(function (opt, idx) {
+ opt.addEventListener("click", function () {
+ commit(opt.dataset.value);
+ });
+ opt.addEventListener("mouseenter", function () {
+ preview(idx);
+ });
+ });
+
+ document.addEventListener("keydown", function (e) {
+ if ((e.key === "t" || e.key === "/") && !e.ctrlKey && !e.metaKey && !e.altKey) {
+ var tag = document.activeElement && document.activeElement.tagName;
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
+ e.preventDefault();
+ toggleOverlay();
+ return;
+ }
+ if (overlay.hidden) return;
+ var current = document.activeElement;
+ var idx = options.indexOf(current);
+ if (e.key === "ArrowDown") {
+ e.preventDefault();
+ var nextIdx = idx >= 0 ? Math.min(options.length - 1, idx + 1) : 0;
+ preview(nextIdx);
+ } else if (e.key === "ArrowUp") {
+ e.preventDefault();
+ var prevIdx = idx >= 0 ? Math.max(0, idx - 1) : options.length - 1;
+ preview(prevIdx);
+ } else if (e.key === "Enter" && idx >= 0) {
+ e.preventDefault();
+ commit(options[idx].dataset.value);
+ } else if (e.key === "Escape") {
+ e.preventDefault();
+ revert();
+ }
+ });
+
+ var themeHint = document.getElementById("theme-hint");
+ if (localStorage.getItem("herdr-theme-hint-seen") === "1") {
+ themeHint.classList.add("is-seen");
+ }
+ themeHint.addEventListener("mouseenter", function () {
+ localStorage.setItem("herdr-theme-hint-seen", "1");
+ themeHint.classList.add("is-seen");
+ }, { once: true });
+ themeHint.addEventListener("click", toggleOverlay);
+ document.getElementById("theme-close-btn").addEventListener("click", revert);
+
+ setPalette(saved);
+ updateUI(saved);
+ })();
+
+ (function () {
var menu = document.getElementById("logo-menu");
var copyButton = document.getElementById("copy-logo-url");
var logos = document.querySelectorAll(".brand-logo");
@@ -770,135 +987,6 @@ $ herdr</code></pre>
})();
(function () {
- var hero = document.getElementById("hero");
- var pasture = hero && hero.querySelector(".hero-pasture");
- var reduceMotion = window.matchMedia(
- "(prefers-reduced-motion: reduce)",
- ).matches;
-
- if (hero && pasture && !reduceMotion) {
- var sheepRight = [
- [" ,ww", " wWWWWWWW)", " `WWWWWW'", " /I I\\"],
- [" ,ww", " wWWWWWWW)", " `WWWWWW'", " I\\ /I "],
- ];
- var sheepLeft = [
- [" ww,", "(WWWWWWWw", " 'WWWWWW`", " /I I\\"],
- [" ww,", "(WWWWWWWw", " 'WWWWWW`", " I\\ /I "],
- ];
- var colors = [
- "31,111,104",
- "37,99,235",
- "21,26,33",
- "154,106,0",
- ];
-
- var heroWidth = hero.offsetWidth;
- var heroHeight = hero.offsetHeight;
- var heroRect = hero.getBoundingClientRect();
- var mouseX = -9999;
- var mouseY = -9999;
- var flock = [];
- var count = window.matchMedia("(max-width: 900px)").matches
- ? 8
- : 16;
-
- document.addEventListener("mousemove", function (event) {
- mouseX = event.clientX - heroRect.left;
- mouseY = event.clientY - heroRect.top;
- });
- document.addEventListener("mouseleave", function () {
- mouseX = -9999;
- mouseY = -9999;
- });
- window.addEventListener("resize", function () {
- heroWidth = hero.offsetWidth;
- heroHeight = hero.offsetHeight;
- heroRect = hero.getBoundingClientRect();
- });
- window.addEventListener("scroll", function () {
- heroRect = hero.getBoundingClientRect();
- });
-
- for (var i = 0; i < count; i += 1) {
- var sheep = document.createElement("pre");
- sheep.className = "sheep-el";
- var color = colors[i % colors.length];
- var opacity = 0.045 + Math.random() * 0.045;
- var size = 8.5 + Math.random() * 4.5;
- sheep.style.cssText =
- "font-size:" +
- size +
- "px;color:rgba(" +
- color +
- "," +
- opacity +
- ")";
- pasture.appendChild(sheep);
-
- flock.push({
- el: sheep,
- x: Math.random() * heroWidth,
- y: 24 + Math.random() * Math.max(heroHeight - 64, 120),
- dir: Math.random() > 0.5 ? 1 : -1,
- speed: 0.08 + Math.random() * 0.2,
- frame: 0,
- frameTime: 0,
- frameInterval: 420 + Math.random() * 320,
- shoveX: 0,
- shoveY: 0,
- });
- }
-
- var lastFrame = 0;
- function tick(timestamp) {
- var delta = Math.min(timestamp - lastFrame, 100);
- lastFrame = timestamp;
-
- for (var i = 0; i < flock.length; i += 1) {
- var sheep = flock[i];
- sheep.frameTime += delta;
- if (sheep.frameTime > sheep.frameInterval) {
- sheep.frameTime = 0;
- sheep.frame ^= 1;
- }
-
- var dx = sheep.x - mouseX;
- var dy = sheep.y - mouseY;
- var distance = Math.sqrt(dx * dx + dy * dy);
- if (distance < 150 && distance > 1) {
- var force = (1 - distance / 150) * 0.48;
- sheep.shoveX += (dx / distance) * force;
- sheep.shoveY += (dy / distance) * force;
- }
-
- sheep.x += sheep.shoveX;
- sheep.y += sheep.shoveY;
- sheep.shoveX *= 0.965;
- sheep.shoveY *= 0.965;
- sheep.x += sheep.dir * sheep.speed * (delta / 16);
-
- if (sheep.dir > 0 && sheep.x > heroWidth + 120) sheep.x = -120;
- if (sheep.dir < 0 && sheep.x < -120) sheep.x = heroWidth + 120;
- if (sheep.y < -48) sheep.y = heroHeight + 24;
- if (sheep.y > heroHeight + 48) sheep.y = -24;
-
- var frames = sheep.dir > 0 ? sheepRight : sheepLeft;
- sheep.el.textContent = frames[sheep.frame].join("\n");
- sheep.el.style.transform =
- "translate3d(" + sheep.x + "px," + sheep.y + "px,0)";
- }
-
- requestAnimationFrame(tick);
- }
-
- requestAnimationFrame(function (timestamp) {
- lastFrame = timestamp;
- tick(timestamp);
- });
- }
- })();
-
- (function () {
var copyButton = document.getElementById("copy-btn");
var command = document.getElementById("install-cmd");
var methods = Array.prototype.slice.call(
@@ -936,6 +1024,22 @@ $ herdr</code></pre>
}
});
})();
+
+ (function () {
+ var frames = ["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];
+ var els = document.querySelectorAll(".braille-spinner");
+ if (!els.length) return;
+ var states = Array.prototype.map.call(els, function () { return 0; });
+ els.forEach(function (el, idx) {
+ el.textContent = frames[0];
+ });
+ setInterval(function () {
+ els.forEach(function (el, idx) {
+ states[idx] = (states[idx] + 1) % frames.length;
+ el.textContent = frames[states[idx]];
+ });
+ }, 80);
+ })();
</script>
</body>
</html>