WitNote / website /src /App.jsx
harvesthealth's picture
Upload folder using huggingface_hub
f7044f4 verified
import { useEffect, useRef } from "react";
import logo from "../../assets/icon.png";
const IconClaude = () => (
<svg viewBox="0 0 16 16" width="18" height="18" fill="currentColor">
<path d="m3.127 10.604 3.135-1.76.053-.153-.053-.085H6.11l-.525-.032-1.791-.048-1.554-.065-1.505-.08-.38-.081L0 7.832l.036-.234.32-.214.455.04 1.009.069 1.513.105 1.097.064 1.626.17h.259l.036-.105-.089-.065-.068-.064-1.566-1.062-1.695-1.121-.887-.646-.48-.327-.243-.306-.104-.67.435-.48.585.04.15.04.593.456 1.267.981 1.654 1.218.242.202.097-.068.012-.049-.109-.181-.9-1.626-.96-1.655-.428-.686-.113-.411a2 2 0 0 1-.068-.484l.496-.674L4.446 0l.662.089.279.242.411.94.666 1.48 1.033 2.014.302.597.162.553.06.17h.105v-.097l.085-1.134.157-1.392.154-1.792.052-.504.25-.605.497-.327.387.186.319.456-.045.294-.19 1.23-.37 1.93-.243 1.29h.142l.161-.16.654-.868 1.097-1.372.484-.545.565-.601.363-.287h.686l.505.751-.226.775-.707.895-.585.759-.839 1.13-.524.904.048.072.125-.012 1.897-.403 1.024-.186 1.223-.21.553.258.06.263-.218.536-1.307.323-1.533.307-2.284.54-.028.02.032.04 1.029.098.44.024h1.077l2.005.15.525.346.315.424-.053.323-.807.411-3.631-.863-.872-.218h-.12v.073l.726.71 1.331 1.202 1.667 1.55.084.383-.214.302-.226-.032-1.464-1.101-.565-.497-1.28-1.077h-.084v.113l.295.432 1.557 2.34.08.718-.112.234-.404.141-.444-.08-.911-1.28-.94-1.44-.759-1.291-.093.053-.448 4.821-.21.246-.484.186-.403-.307-.214-.496.214-.98.258-1.28.21-1.016.19-1.263.112-.42-.008-.028-.092.012-.953 1.307-1.448 1.957-1.146 1.227-.274.109-.477-.247.045-.44.266-.39 1.586-2.018.956-1.25.617-.723-.004-.105h-.036l-4.212 2.736-.75.096-.324-.302.04-.496.154-.162 1.267-.871z"/>
</svg>
);
const IconCodex = () => (
<svg viewBox="0 0 16 16" width="18" height="18" fill="currentColor">
<path d="M14.949 6.547a3.94 3.94 0 0 0-.348-3.273 4.11 4.11 0 0 0-4.4-1.934 4.1 4.1 0 0 0-1.778-.613 4.15 4.15 0 0 0-2.118-.114 4.1 4.1 0 0 0-1.891.948 4.04 4.04 0 0 0-1.158 1.753 4.1 4.1 0 0 0-1.563.679 4 4 0 0 0-1.14 1.254 3.99 3.99 0 0 0 .502 4.731 3.94 3.94 0 0 0 .346 3.274 4.11 4.11 0 0 0 4.402 1.933c.382.425.852.764 1.377.995.526.231 1.095.35 1.67.346 1.78.002 3.358-1.132 3.901-2.804a4.1 4.1 0 0 0 1.563-.68 4 4 0 0 0 1.14-1.253 3.99 3.99 0 0 0-.506-4.716m-6.097 8.406a3.05 3.05 0 0 1-1.945-.694l.096-.054 3.23-1.838a.53.53 0 0 0 .265-.455v-4.49l1.366.778q.02.011.025.035v3.722c-.003 1.653-1.361 2.992-3.037 2.996m-6.53-2.75a2.95 2.95 0 0 1-.36-2.01l.095.057L5.29 12.09a.53.53 0 0 0 .527 0l3.949-2.246v1.555a.05.05 0 0 1-.022.041L6.473 13.3c-1.454.826-3.311.335-4.15-1.098m-.85-6.94A3.02 3.02 0 0 1 3.07 3.949v3.785a.51.51 0 0 0 .262.451l3.93 2.237-1.366.779a.05.05 0 0 1-.048 0L2.585 9.342a2.98 2.98 0 0 1-1.113-4.094zm11.216 2.571L8.747 5.576l1.362-.776a.05.05 0 0 1 .048 0l3.265 1.86a3 3 0 0 1 1.173 1.207 2.96 2.96 0 0 1-.27 3.2 3.05 3.05 0 0 1-1.36.997V8.279a.52.52 0 0 0-.276-.445m1.36-2.015-.097-.057-3.226-1.855a.53.53 0 0 0-.53 0L6.249 6.153V4.598a.04.04 0 0 1 .019-.04L9.533 2.7a3.07 3.07 0 0 1 3.257.139c.474.325.843.778 1.066 1.303.223.526.289 1.103.191 1.664zM5.503 8.575 4.139 7.8a.05.05 0 0 1-.026-.037V4.049c0-.57.166-1.127.476-1.607s.752-.864 1.275-1.105a3.08 3.08 0 0 1 3.234.41l-.096.054-3.23 1.838a.53.53 0 0 0-.265.455zm.742-1.577 1.758-1 1.762 1v2l-1.755 1-1.762-1z"/>
</svg>
);
const IconOpenClaw = () => (
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round">
<path d="M8 9C6.5 7 4.5 5 3.5 4.5C2.5 4 2 5 3 6C4 7 6 8 7.5 9"/><path d="M12 9C13.5 7 15.5 5 16.5 4.5C17.5 4 18 5 17 6C16 7 14 8 12.5 9"/>
<path d="M7.5 9C7 11 7.5 14.5 10 17.5C12.5 14.5 13 11 12.5 9L10 8Z"/>
<line x1="8.5" y1="4" x2="7" y2="1.5"/><line x1="11.5" y1="4" x2="13" y2="1.5"/>
</svg>
);
const IconNanobot = () => (
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.3" strokeLinecap="round" strokeLinejoin="round">
<path d="M4.5 8.5L3 3L7.5 7"/><path d="M15.5 8.5L17 3L12.5 7"/>
<circle cx="10" cy="12.5" r="5.5"/>
<circle cx="7.8" cy="11.5" r="1.2" fill="currentColor" stroke="none"/><circle cx="12.2" cy="11.5" r="1.2" fill="currentColor" stroke="none"/>
<path d="M9.2 14L10 14.8L10.8 14"/>
</svg>
);
const IconCLI = () => (
<svg viewBox="0 0 20 20" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
<path d="M5 7L9 10L5 13"/><line x1="11" y1="14" x2="16" y2="14"/>
</svg>
);
const clientIcons = { claude: IconClaude, codex: IconCodex, openclaw: IconOpenClaw, nanobot: IconNanobot, any: IconCLI };
const clients = [
{ key: "claude", label: "Claude Code" },
{ key: "codex", label: "Codex" },
{ key: "openclaw", label: "OpenClaw" },
{ key: "nanobot", label: "nanobot" },
{ key: "any", label: "Any CLI" }
];
const orbitClients = clients;
const features = [
{ title: "Shared task graph", body: "One board for blockers, priority, ownership, and progress across all agents." },
{ title: "Persistent coordination", body: "Handoffs, aliases, and notes stay visible after prompts scroll away." },
{ title: "Git-aware execution", body: "Real repos, worktrees, diffs, and mergeable state keep the swarm grounded." }
];
const steps = [
{ num: "01", title: "Install", body: "Get the CLI. Add P2P transport when the team needs it.", code: 'pip install clawteam\npip install "clawteam[p2p]"' },
{ num: "02", title: "Model the work", body: "Create a team and define tasks so the board tracks the project.", code: 'clawteam team spawn-team my-team -d "Docs + engineering"\nclawteam task create my-team "Build landing page" --priority urgent' },
{ num: "03", title: "Spawn agents", body: "Run any terminal-native client from the same surface.", code: "clawteam spawn tmux claude-code --team my-team --agent-name builder\nclawteam spawn tmux codex --team my-team --agent-name reviewer" }
];
const docs = [
{ title: "Quick Start", body: "Install to first running swarm.", href: "https://github.com/HKUDS/ClawTeam#-quick-start" },
{ title: "Skill Guide", body: "Agent-facing operating guide.", href: "skills/clawteam/SKILL.md" },
{ title: "CLI Reference", body: "Commands, flags, and runtime details.", href: "skills/clawteam/references/cli-reference.md" },
{ title: "Workflows", body: "Practical patterns for real teams.", href: "skills/clawteam/references/workflows.md" }
];
function HalfGlobe() {
const ref = useRef(null);
useEffect(() => {
const canvas = ref.current;
const ctx = canvas.getContext("2d");
let w = 0, h = 0, dpr = 1, R = 0, rot = 0, raf = 0;
let tilt = -0.45;
const agents = [
// upper arc (south pole region, appears at top)
{ theta: 0.3, phi: 2.6, r: 249, g: 115, b: 22 },
{ theta: 1.5, phi: 2.5, r: 129, g: 140, b: 248 },
{ theta: 2.7, phi: 2.7, r: 34, g: 197, b: 94 },
{ theta: 3.8, phi: 2.55, r: 249, g: 115, b: 22 },
{ theta: 5.0, phi: 2.65, r: 129, g: 140, b: 248 },
// middle band
{ theta: 0.8, phi: 2.1, r: 34, g: 197, b: 94 },
{ theta: 1.9, phi: 2.2, r: 249, g: 115, b: 22 },
{ theta: 3.2, phi: 2.0, r: 129, g: 140, b: 248 },
{ theta: 4.4, phi: 2.15, r: 34, g: 197, b: 94 },
{ theta: 5.6, phi: 2.1, r: 249, g: 115, b: 22 },
// lower band (equator, appears near bottom edge)
{ theta: 0.5, phi: 1.6, r: 129, g: 140, b: 248 },
{ theta: 1.7, phi: 1.5, r: 249, g: 115, b: 22 },
{ theta: 3.0, phi: 1.55, r: 34, g: 197, b: 94 },
{ theta: 4.2, phi: 1.65, r: 129, g: 140, b: 248 },
{ theta: 5.4, phi: 1.5, r: 249, g: 115, b: 22 }
];
const conns = [[0,1],[1,2],[2,3],[3,4],[4,0],[0,5],[1,6],[2,7],[3,8],[4,9],[5,6],[6,7],[7,8],[8,9],[9,5],[5,10],[6,11],[7,12],[8,13],[9,14],[10,11],[11,12],[12,13],[13,14],[14,10]];
const sph = (t, p) => ({ x: Math.sin(p)*Math.cos(t), y: Math.cos(p), z: Math.sin(p)*Math.sin(t) });
const rX = (p, a) => { const c=Math.cos(a),s=Math.sin(a); return {x:p.x, y:p.y*c-p.z*s, z:p.y*s+p.z*c}; };
const rY = (p, a) => { const c=Math.cos(a),s=Math.sin(a); return {x:p.x*c-p.z*s, y:p.y, z:p.x*s+p.z*c}; };
const xform = (t, p) => rX(rY(sph(t, p), rot), tilt);
const cx = () => w * 0.5;
const cy = () => h + R * 0.08;
const proj = (p) => { const d=3.2, sc=d/(d-p.z); return {x:cx()+p.x*R*sc, y:cy()+p.y*R*sc, z:p.z, scale:sc}; };
const resize = () => {
const rc = canvas.getBoundingClientRect();
dpr = Math.min(window.devicePixelRatio||1, 2);
w = rc.width; h = rc.height;
R = w * 0.3;
canvas.width = Math.round(w*dpr); canvas.height = Math.round(h*dpr);
ctx.setTransform(dpr,0,0,dpr,0,0);
};
const onScroll = () => {
const rect = canvas.getBoundingClientRect();
const vh = window.innerHeight;
const center = rect.top + rect.height / 2;
const progress = Math.max(0, Math.min(1, 1 - center / vh));
tilt = -1.4 + progress * 2.8;
};
const drawGrid = () => {
const glow = ctx.createRadialGradient(cx(),cy(),0, cx(),cy(),R*1.15);
glow.addColorStop(0,"rgba(99,102,241,0.05)"); glow.addColorStop(0.4,"rgba(249,115,22,0.025)"); glow.addColorStop(1,"transparent");
ctx.beginPath(); ctx.arc(cx(),cy(),R*1.15,0,Math.PI*2); ctx.fillStyle=glow; ctx.fill();
ctx.lineWidth=1;
for(let i=0;i<13;i++){const phi=((i+1)/14)*Math.PI; ctx.beginPath(); ctx.strokeStyle="rgba(148,163,184,0.16)"; let on=false;
for(let j=0;j<=100;j++){const p=proj(xform((j/100)*Math.PI*2,phi)); if(p.z<-0.35||p.y>h+5){on=false;continue;} if(!on){ctx.moveTo(p.x,p.y);on=true;}else ctx.lineTo(p.x,p.y);} ctx.stroke();}
for(let i=0;i<20;i++){const t=(i/20)*Math.PI*2; ctx.beginPath(); ctx.strokeStyle="rgba(148,163,184,0.16)"; let on=false;
for(let j=0;j<=100;j++){const p=proj(xform(t,(j/100)*Math.PI)); if(p.z<-0.35||p.y>h+5){on=false;continue;} if(!on){ctx.moveTo(p.x,p.y);on=true;}else ctx.lineTo(p.x,p.y);} ctx.stroke();}
ctx.beginPath(); ctx.arc(cx(),cy(),R*1.08,0,Math.PI*2);
ctx.setLineDash([6,12]); ctx.strokeStyle="rgba(148,163,184,0.1)"; ctx.lineWidth=1; ctx.stroke(); ctx.setLineDash([]);
};
const drawConns = () => {
conns.forEach(([i,j])=>{
const a=proj(xform(agents[i].theta,agents[i].phi)), b=proj(xform(agents[j].theta,agents[j].phi));
if(a.z<-0.5||b.z<-0.5||a.y>h||b.y>h) return;
const fade=Math.min((a.z+0.5)/0.8,(b.z+0.5)/0.8), dist=Math.hypot(b.x-a.x,b.y-a.y);
if(dist<2) return;
const mx=(a.x+b.x)/2, my=(a.y+b.y)/2, nx=-(b.y-a.y)/dist, ny=(b.x-a.x)/dist;
ctx.beginPath(); ctx.moveTo(a.x,a.y); ctx.quadraticCurveTo(mx+nx*dist*0.12,my+ny*dist*0.12,b.x,b.y);
ctx.strokeStyle=`rgba(148,163,184,${0.13*fade})`; ctx.lineWidth=0.8; ctx.stroke();
});
};
const drawAgents = (time) => {
agents.forEach(agent=>{
const p=proj(xform(agent.theta,agent.phi));
if(p.z<-0.5||p.y>h) return;
const fade=Math.min(1,(p.z+0.5)/0.8), pulse=1+0.2*Math.sin(time*0.002+agent.theta*5);
const {r,g,b}=agent, gr=26*p.scale*pulse;
const grd=ctx.createRadialGradient(p.x,p.y,0,p.x,p.y,gr);
grd.addColorStop(0,`rgba(${r},${g},${b},${0.4*fade})`); grd.addColorStop(1,"transparent");
ctx.beginPath(); ctx.arc(p.x,p.y,gr,0,Math.PI*2); ctx.fillStyle=grd; ctx.fill();
ctx.beginPath(); ctx.arc(p.x,p.y,4.5*p.scale*pulse,0,Math.PI*2); ctx.fillStyle=`rgba(${r},${g},${b},${0.95*fade})`; ctx.fill();
ctx.beginPath(); ctx.arc(p.x,p.y,10*p.scale*pulse,0,Math.PI*2); ctx.strokeStyle=`rgba(${r},${g},${b},${0.2*fade})`; ctx.lineWidth=1; ctx.stroke();
});
};
const draw = (time) => { ctx.clearRect(0,0,w,h); drawGrid(); drawConns(); drawAgents(time); rot+=0.0018; raf=requestAnimationFrame(draw); };
resize(); onScroll(); draw(0);
window.addEventListener("resize",resize); window.addEventListener("scroll",onScroll,{passive:true});
return ()=>{ cancelAnimationFrame(raf); window.removeEventListener("resize",resize); window.removeEventListener("scroll",onScroll); };
},[]);
return (
<div className="globe-section">
<div className="globe-glow" aria-hidden="true" />
<canvas ref={ref} className="globe-canvas" aria-hidden="true" />
{orbitClients.map(c=>{ const Icon=clientIcons[c.key]; return <span key={c.key} className={`orbit-label orbit-${c.key}`}><Icon/>{c.label}</span>; })}
<div className="globe-fade-top" aria-hidden="true" />
<div className="globe-fade-bottom" aria-hidden="true" />
</div>
);
}
function TerminalMockup() {
return (
<div className="terminal">
<div className="terminal-bar"><span className="terminal-dot"/><span className="terminal-dot"/><span className="terminal-dot"/><span className="terminal-title">clawteam</span></div>
<div className="terminal-body">
<div className="terminal-line"><span className="t-prompt">$</span> clawteam team spawn-team docs-sprint</div>
<div className="terminal-line t-output"><span className="t-success">{"\u2713"}</span> Team &quot;docs-sprint&quot; created</div><br/>
<div className="terminal-line"><span className="t-prompt">$</span> clawteam spawn tmux claude-code --agent-name builder</div>
<div className="terminal-line t-output"><span className="t-active">{"\u25cf"}</span> Agent &quot;builder&quot; spawned in tmux</div><br/>
<div className="terminal-line"><span className="t-prompt">$</span> clawteam team status docs-sprint</div>
<div className="terminal-output-block">
<div className="t-status-header">docs-sprint <span className="t-dim">3 agents active</span></div>
<div className="t-status-row"><span className="t-success">{"\u25cf"}</span> T-001 Build landing page <span className="t-badge t-done">done</span></div>
<div className="t-status-row"><span className="t-active">{"\u25cf"}</span> T-002 Write API docs <span className="t-badge t-progress">active</span></div>
<div className="t-status-row"><span className="t-dim">{"\u25cb"}</span> T-003 Review &amp; merge <span className="t-badge t-blocked">blocked</span></div>
</div>
<div className="terminal-line" style={{marginTop:10}}><span className="t-prompt">$</span> <span className="terminal-cursor"/></div>
</div>
</div>
);
}
function App() {
return (
<div className="page">
<div className="bg-gradient" aria-hidden="true"/>
<header className="header">
<div className="shell header-inner">
<a className="logo" href="#top"><img src={logo} alt="ClawTeam"/><strong>ClawTeam</strong></a>
<nav className="nav"><a href="#features">Features</a><a href="#workflow">How it works</a><a href="#docs">Docs</a></nav>
<a className="btn-primary" href="https://github.com/HKUDS/ClawTeam" target="_blank" rel="noreferrer">GitHub</a>
</div>
</header>
<main>
<section className="hero shell" id="top">
<div className="hero-content">
<p className="badge">Agent swarm orchestration</p>
<h1>Coordinate any coding agent from one CLI</h1>
<p className="hero-sub">ClawTeam is the coordination layer for Claude Code, Codex, OpenClaw, nanobot, and any terminal-native client that needs to plan, delegate, and ship together.</p>
<div className="hero-cta">
<a className="btn-primary" href="https://github.com/HKUDS/ClawTeam#-quick-start" target="_blank" rel="noreferrer">Get started</a>
<a className="btn-ghost" href="skills/clawteam/references/cli-reference.md">CLI Reference</a>
</div>
</div>
<div className="hero-visual"><TerminalMockup/></div>
</section>
<HalfGlobe/>
<section className="clients shell">
<span className="clients-label">Works with</span>
<div className="clients-list">{clients.map(c=>{ const Icon=clientIcons[c.key]; return <span key={c.key}><Icon/>{c.label}</span>; })}</div>
</section>
<section className="features shell" id="features">
<div className="section-header"><p className="section-label">Core capabilities</p><h2>Built for agent teams, not isolated sessions</h2></div>
<div className="features-grid">{features.map(f=><article className="feature-card" key={f.title}><h3>{f.title}</h3><p>{f.body}</p></article>)}</div>
</section>
<section className="workflow shell" id="workflow">
<div className="section-header"><p className="section-label">How it works</p><h2>Three steps to a running swarm</h2></div>
<div className="steps">{steps.map(s=><div className="step" key={s.num}><div className="step-info"><span className="step-num">{s.num}</span><h3>{s.title}</h3><p>{s.body}</p></div><pre className="step-code"><code>{s.code}</code></pre></div>)}</div>
</section>
<section className="docs shell" id="docs">
<div className="section-header"><p className="section-label">Documentation</p><h2>Learn more</h2></div>
<div className="docs-grid">{docs.map(d=><a className="doc-card" key={d.title} href={d.href} target={d.href.startsWith("http")?"_blank":undefined} rel={d.href.startsWith("http")?"noreferrer":undefined}><strong>{d.title}</strong><span>{d.body}</span><span className="doc-arrow">{"\u2192"}</span></a>)}</div>
</section>
</main>
<footer className="footer shell">
<span>ClawTeam</span>
<div className="footer-links"><a href="https://github.com/HKUDS/ClawTeam">GitHub</a><a href="skills/clawteam/SKILL.md">Skill</a><a href="skills/clawteam/references/cli-reference.md">CLI Reference</a></div>
</footer>
</div>
);
}
export default App;