diff --git a/.github/workflows/deploy-site.yml b/.github/workflows/deploy-site.yml index 44da745b9f..480b236f84 100644 --- a/.github/workflows/deploy-site.yml +++ b/.github/workflows/deploy-site.yml @@ -1,12 +1,11 @@ name: Deploy Site on: - release: - types: [published] push: branches: [main] paths: - 'website/**' + - 'landingpage/**' - 'skills/**' - 'optional-skills/**' - '.github/workflows/deploy-site.yml' @@ -21,14 +20,8 @@ concurrency: cancel-in-progress: false jobs: - deploy-vercel: - if: github.event_name == 'release' - runs-on: ubuntu-latest - steps: - - name: Trigger Vercel Deploy - run: curl -X POST "${{ secrets.VERCEL_DEPLOY_HOOK }}" - - deploy-docs: + build-and-deploy: + # Only run on the upstream repository, not on forks if: github.repository == 'NousResearch/hermes-agent' runs-on: ubuntu-latest environment: @@ -69,10 +62,20 @@ jobs: run: npm run build working-directory: website + - name: Stage deployment + run: | + mkdir -p _site/docs + # Landing page at root + cp -r landingpage/* _site/ + # Docusaurus at /docs/ + cp -r website/build/* _site/docs/ + # CNAME so GitHub Pages keeps the custom domain between deploys + echo "hermes-agent.nousresearch.com" > _site/CNAME + - name: Upload artifact uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 with: - path: website/build + path: _site - name: Deploy to GitHub Pages id: deploy diff --git a/landingpage/apple-touch-icon.png b/landingpage/apple-touch-icon.png new file mode 100644 index 0000000000..c5da175f8e Binary files /dev/null and b/landingpage/apple-touch-icon.png differ diff --git a/landingpage/favicon-16x16.png b/landingpage/favicon-16x16.png new file mode 100644 index 0000000000..5bc67ef224 Binary files /dev/null and b/landingpage/favicon-16x16.png differ diff --git a/landingpage/favicon-32x32.png b/landingpage/favicon-32x32.png new file mode 100644 index 0000000000..8db2977a5b Binary files /dev/null and b/landingpage/favicon-32x32.png differ diff --git a/landingpage/favicon.ico b/landingpage/favicon.ico new file mode 100644 index 0000000000..8586c395f6 Binary files /dev/null and b/landingpage/favicon.ico differ diff --git a/landingpage/hermes-agent-banner.png b/landingpage/hermes-agent-banner.png new file mode 100644 index 0000000000..2c4a160ceb Binary files /dev/null and b/landingpage/hermes-agent-banner.png differ diff --git a/landingpage/icon-192.png b/landingpage/icon-192.png new file mode 100644 index 0000000000..126a395793 Binary files /dev/null and b/landingpage/icon-192.png differ diff --git a/landingpage/icon-512.png b/landingpage/icon-512.png new file mode 100644 index 0000000000..c5b4c63a57 Binary files /dev/null and b/landingpage/icon-512.png differ diff --git a/landingpage/index.html b/landingpage/index.html new file mode 100644 index 0000000000..e24ed11c48 --- /dev/null +++ b/landingpage/index.html @@ -0,0 +1,665 @@ + + + + + + Hermes Agent — An Agent That Grows With You + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+ + Open Source • MIT License +
+ + + + +

+ An agent that
+ grows with you. +

+ +

+ It's not a coding copilot tethered to an IDE or a chatbot wrapper + around a single API. It's an autonomous agent that + lives on your server, remembers what it learns, and gets more capable + the longer it runs. +

+ +
+
+
+
+ + + +
+
+ +
+
+
+ $ + curl -fsSL + https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh + | bash + +
+
+

+ Works on Linux, macOS & WSL2 · No prerequisites · Installs + everything automatically +

+
+ + +
+
+ +
+
+
+

Get started in 60 seconds

+
+ +
+
+
1
+
+

Install

+
+
+
+ +
+ +
+
curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash
+
+

+ Installs uv, Python 3.11, clones the repo, sets up everything. + No sudo needed. +

+
+
+ +
+
2
+
+

Configure

+
+
+ bash + +
+
# Interactive setup wizard
+hermes setup
+
+# Or choose your model
+hermes model
+
+

+ Connect to Nous Portal (OAuth), OpenRouter (API key), or your + own endpoint. +

+
+
+ +
+
3
+
+

Start chatting

+
+
+ bash + +
+
hermes
+
+

+ That's it. Full interactive CLI with tools, memory, and skills. +

+
+
+ +
+
4
+
+

+ Go multi-platform (optional) +

+
+
+ bash + +
+
# Interactive gateway setup wizard
+hermes gateway setup
+
+# Start the messaging gateway
+hermes gateway
+
+# Install as a system service
+hermes gateway install
+
+

+ Walk through connecting Telegram, Discord, Slack, or WhatsApp. + Runs as a systemd service. +

+
+
+ +
+
5
+
+

Keep it up to date

+
+
+ bash + +
+
hermes update
+
+

+ Pulls the latest changes and reinstalls dependencies. Run + anytime to get new features and fixes. +

+
+
+
+ +
+

+ Native Windows support is extremely experimental and unsupported. + Please install + WSL2 + and run Hermes Agent from there. +

+
+
+
+ + +
+
+
+

See it in action

+
+ +
+
+
+ + + +
+ hermes +
+
+
+
+
+ + +
+
+
+

Features

+
+ +
+
+
+
+ + + +
+

Lives Where You Do

+
+

+ Telegram, Discord, Slack, WhatsApp, and CLI from a single gateway + — start on one, pick up on another. +

+
+ +
+
+
+ + + + +
+

Grows the Longer It Runs

+
+

+ Persistent memory and auto-generated skills — it learns your + projects and never forgets how it solved a problem. +

+
+ +
+
+
+ + + + +
+

Scheduled Automations

+
+

+ Natural language cron scheduling for reports, backups, and + briefings — running unattended through the gateway. +

+
+ +
+
+
+ + + + + + +
+

Delegates & Parallelizes

+
+

+ Isolated subagents with their own conversations, terminals, and + Python RPC scripts for zero-context-cost pipelines. +

+
+ +
+
+
+ + + + +
+

Real Sandboxing

+
+

+ Five backends — local, Docker, SSH, Singularity, Modal — with + container hardening and namespace isolation. +

+
+ +
+
+
+ + + + + +
+

Full Web & Browser Control

+
+

+ Web search, browser automation, vision, image generation, + text-to-speech, and multi-model reasoning. +

+
+
+ +
+ +
+ +
+
+
+

Tools

+

+ 40+ built-in — web search, terminal, file system, browser + automation, vision, image generation, text-to-speech, code + execution, subagent delegation, memory, task planning, cron + scheduling, multi-model reasoning, and more. +

+
+ +
+

Platforms

+

+ Telegram, Discord, Slack, WhatsApp, Signal, Email, and CLI — all + from a single gateway. Connect to + Nous Portal, OpenRouter, or any OpenAI-compatible API. +

+
+ +
+

Environments

+

+ Run locally, in Docker, over SSH, on Modal, Daytona, or + Singularity. Container hardening with read-only root, dropped + capabilities, and namespace isolation. +

+
+ +
+

Skills

+

+ 40+ bundled skills covering MLOps, GitHub workflows, research, + and more. The agent creates new skills on the fly and shares + them via the open + agentskills.io + format. Install community skills from + ClawHub, + LobeHub, and GitHub. +

+
+ +
+

Research

+

+ Batch trajectory generation with parallel workers and + checkpointing. Atropos integration for RL training. Export to + ShareGPT for fine-tuning with trajectory compression. +

+
+
+
+
+
+ + + + + + diff --git a/landingpage/nous-logo.png b/landingpage/nous-logo.png new file mode 100644 index 0000000000..cfea9a6613 Binary files /dev/null and b/landingpage/nous-logo.png differ diff --git a/landingpage/script.js b/landingpage/script.js new file mode 100644 index 0000000000..4cd097bdb2 --- /dev/null +++ b/landingpage/script.js @@ -0,0 +1,521 @@ +// ========================================================================= +// Hermes Agent Landing Page — Interactions +// ========================================================================= + +// --- Platform install commands --- +const PLATFORMS = { + linux: { + command: + "curl -fsSL https://raw.githubusercontent.com/NousResearch/hermes-agent/main/scripts/install.sh | bash", + prompt: "$", + note: "Works on Linux, macOS & WSL2 · No prerequisites · Installs everything automatically", + stepNote: + "Installs uv, Python 3.11, clones the repo, sets up everything. No sudo needed.", + }, +}; + +function detectPlatform() { + return "linux"; +} + +function switchPlatform(platform) { + const cfg = PLATFORMS[platform]; + if (!cfg) return; + + // Update hero install widget + const commandEl = document.getElementById("install-command"); + const promptEl = document.getElementById("install-prompt"); + const noteEl = document.getElementById("install-note"); + + if (commandEl) commandEl.textContent = cfg.command; + if (promptEl) promptEl.textContent = cfg.prompt; + if (noteEl) noteEl.textContent = cfg.note; + + // Update active tab in hero + document.querySelectorAll(".install-tab").forEach((tab) => { + tab.classList.toggle("active", tab.dataset.platform === platform); + }); + + // Sync the step section tabs too + switchStepPlatform(platform); +} + +function switchStepPlatform(platform) { + const cfg = PLATFORMS[platform]; + if (!cfg) return; + + const commandEl = document.getElementById("step1-command"); + const copyBtn = document.getElementById("step1-copy"); + const noteEl = document.getElementById("step1-note"); + + if (commandEl) commandEl.textContent = cfg.command; + if (copyBtn) copyBtn.setAttribute("data-text", cfg.command); + if (noteEl) noteEl.textContent = cfg.stepNote; + + // Update active tab in step section + document.querySelectorAll(".code-tab").forEach((tab) => { + tab.classList.toggle("active", tab.dataset.platform === platform); + }); +} + +function toggleMobileNav() { + document.getElementById("nav-mobile").classList.toggle("open"); + document.getElementById("nav-hamburger").classList.toggle("open"); +} + +function toggleSpecs() { + const wrapper = document.getElementById("specs-wrapper"); + const btn = document.getElementById("specs-toggle"); + const label = btn.querySelector(".toggle-label"); + const isOpen = wrapper.classList.contains("open"); + + if (isOpen) { + wrapper.style.maxHeight = wrapper.scrollHeight + "px"; + requestAnimationFrame(() => { + wrapper.style.maxHeight = "0"; + }); + wrapper.classList.remove("open"); + btn.classList.remove("open"); + if (label) label.textContent = "More details"; + } else { + wrapper.classList.add("open"); + wrapper.style.maxHeight = wrapper.scrollHeight + "px"; + btn.classList.add("open"); + if (label) label.textContent = "Less"; + wrapper.addEventListener( + "transitionend", + () => { + if (wrapper.classList.contains("open")) { + wrapper.style.maxHeight = "none"; + } + }, + { once: true } + ); + } +} + +// --- Copy to clipboard --- +function copyInstall() { + const text = document.getElementById("install-command").textContent; + navigator.clipboard.writeText(text).then(() => { + const btn = document.querySelector(".install-widget-body .copy-btn"); + const original = btn.querySelector(".copy-text").textContent; + btn.querySelector(".copy-text").textContent = "Copied!"; + btn.style.color = "var(--primary-light)"; + setTimeout(() => { + btn.querySelector(".copy-text").textContent = original; + btn.style.color = ""; + }, 2000); + }); +} + +function copyText(btn) { + const text = btn.getAttribute("data-text"); + navigator.clipboard.writeText(text).then(() => { + const original = btn.textContent; + btn.textContent = "Copied!"; + btn.style.color = "var(--primary-light)"; + setTimeout(() => { + btn.textContent = original; + btn.style.color = ""; + }, 2000); + }); +} + +// --- Scroll-triggered fade-in --- +function initScrollAnimations() { + const elements = document.querySelectorAll( + ".feature-card, .install-step, " + + ".section-header, .terminal-window", + ); + + elements.forEach((el) => el.classList.add("fade-in")); + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + // Stagger children within grids + const parent = entry.target.parentElement; + if (parent) { + const siblings = parent.querySelectorAll(".fade-in"); + let idx = Array.from(siblings).indexOf(entry.target); + if (idx < 0) idx = 0; + setTimeout(() => { + entry.target.classList.add("visible"); + }, idx * 60); + } else { + entry.target.classList.add("visible"); + } + observer.unobserve(entry.target); + } + }); + }, + { threshold: 0.1, rootMargin: "0px 0px -40px 0px" }, + ); + + elements.forEach((el) => observer.observe(el)); +} + +// --- Terminal Demo --- +const CURSOR = ''; + +const demoSequence = [ + { type: "prompt", text: "❯ " }, + { + type: "type", + text: "Research the latest approaches to GRPO training and write a summary", + delay: 30, + }, + { type: "pause", ms: 600 }, + { + type: "output", + lines: [ + "", + ' web_search "GRPO reinforcement learning 2026" 1.2s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' web_extract arxiv.org/abs/2402.03300 3.1s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' web_search "GRPO vs PPO ablation results" 0.9s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' web_extract huggingface.co/blog/grpo 2.8s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' write_file ~/research/grpo-summary.md 0.1s', + ], + }, + { type: "pause", ms: 500 }, + { + type: "output", + lines: [ + "", + 'Done! I\'ve written a summary covering:', + "", + ' GRPO\'s group-relative advantage (no critic model needed)', + ' Comparison with PPO/DPO on reasoning benchmarks', + ' Implementation notes for Axolotl and TRL', + "", + 'Saved to ~/research/grpo-summary.md', + ], + }, + { type: "pause", ms: 2500 }, + + { type: "clear" }, + { type: "prompt", text: "❯ " }, + { + type: "type", + text: "Review the PR at NousResearch/hermes-agent#42 and fix any issues", + delay: 30, + }, + { type: "pause", ms: 600 }, + { + type: "output", + lines: [ + "", + ' delegate_task "review PR #42 changes" 2.1s', + ], + }, + { type: "pause", ms: 500 }, + { + type: "output", + lines: [ + ' git diff main..pr-42 0.4s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' patch tools/registry.py 0.1s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' python -m pytest tests/ -x 3.2s', + ], + }, + { type: "pause", ms: 400 }, + { + type: "output", + lines: [ + ' git commit -m "fix: handle empty tool schemas" 0.3s', + ], + }, + { type: "pause", ms: 500 }, + { + type: "output", + lines: [ + "", + 'Found 2 issues in the PR and fixed both:', + "", + ' Empty tool schema crash in registry.py — added guard', + ' Missing error handling in delegate_tool.py — added try/except', + "", + 'Tests pass. Committed the fix and pushed to the PR branch.', + 'I also saved a skill for this PR review pattern.', + ], + }, + { type: "pause", ms: 2500 }, + + { type: "clear" }, + { type: "prompt", text: "❯ " }, + { + type: "type", + text: "How did we fix that Docker networking issue?", + delay: 35, + }, + { type: "pause", ms: 500 }, + { + type: "output", + lines: [ + "", + ' session_search "Docker networking" 1.4s', + ], + }, + { type: "pause", ms: 500 }, + { + type: "output", + lines: [ + "", + 'Found it — from a session on February 12th:', + "", + 'The containers couldn\'t reach each other because the compose', + 'file was using the default bridge network. We switched to a', + 'custom network with driver: overlay, added explicit', + 'aliases, and set dns: 8.8.8.8 as a fallback.', + "", + 'The fix was committed in docker-compose.prod.yml.', + ], + }, + { type: "pause", ms: 3000 }, +]; + +class TerminalDemo { + constructor(container) { + this.container = container; + this.running = false; + this.content = ""; + } + + async start() { + if (this.running) return; + this.running = true; + + while (this.running) { + for (const step of demoSequence) { + if (!this.running) return; + await this.execute(step); + } + this.clear(); + await this.sleep(1000); + } + } + + stop() { + this.running = false; + } + + async execute(step) { + switch (step.type) { + case "prompt": + this.append(`${step.text}`); + break; + case "type": + for (const char of step.text) { + if (!this.running) return; + this.append(`${char}`); + await this.sleep(step.delay || 30); + } + break; + case "output": + for (const line of step.lines) { + if (!this.running) return; + this.append("\n" + line); + await this.sleep(50); + } + break; + case "pause": + await this.sleep(step.ms); + break; + case "clear": + this.clear(); + break; + } + } + + append(html) { + this.content += html; + this.render(); + } + + render() { + this.container.innerHTML = this.content + CURSOR; + this.container.scrollTop = this.container.scrollHeight; + } + + clear() { + this.content = ""; + this.container.innerHTML = ""; + } + + sleep(ms) { + return new Promise((resolve) => setTimeout(resolve, ms)); + } +} + +// --- Noise Overlay (ported from hermes-chat NoiseOverlay) --- +function initNoiseOverlay() { + if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return; + if (typeof THREE === "undefined") return; + + const canvas = document.getElementById("noise-overlay"); + if (!canvas) return; + + const vertexShader = ` + varying vec2 vUv; + void main() { + vUv = uv; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + } + `; + + const fragmentShader = ` + uniform vec2 uRes; + uniform float uDpr, uSize, uDensity, uOpacity; + uniform vec3 uColor; + varying vec2 vUv; + + float hash(vec2 p) { + vec3 p3 = fract(vec3(p.xyx) * 0.1031); + p3 += dot(p3, p3.yzx + 33.33); + return fract((p3.x + p3.y) * p3.z); + } + + void main() { + float n = hash(floor(vUv * uRes / (uSize * uDpr))); + gl_FragColor = vec4(uColor, step(1.0 - uDensity, n)) * uOpacity; + } + `; + + function hexToVec3(hex) { + const c = hex.replace("#", ""); + return new THREE.Vector3( + parseInt(c.substring(0, 2), 16) / 255, + parseInt(c.substring(2, 4), 16) / 255, + parseInt(c.substring(4, 6), 16) / 255, + ); + } + + const renderer = new THREE.WebGLRenderer({ + alpha: true, + canvas, + premultipliedAlpha: false, + }); + renderer.setClearColor(0x000000, 0); + + const scene = new THREE.Scene(); + const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1); + const geo = new THREE.PlaneGeometry(2, 2); + + const mat = new THREE.ShaderMaterial({ + vertexShader, + fragmentShader, + transparent: true, + uniforms: { + uColor: { value: hexToVec3("#8090BB") }, + uDensity: { value: 0.1 }, + uDpr: { value: 1 }, + uOpacity: { value: 0.4 }, + uRes: { value: new THREE.Vector2() }, + uSize: { value: 1.0 }, + }, + }); + + scene.add(new THREE.Mesh(geo, mat)); + + function resize() { + const dpr = window.devicePixelRatio; + const w = window.innerWidth; + const h = window.innerHeight; + renderer.setSize(w, h); + renderer.setPixelRatio(dpr); + mat.uniforms.uRes.value.set(w * dpr, h * dpr); + mat.uniforms.uDpr.value = dpr; + } + + resize(); + window.addEventListener("resize", resize); + + function loop() { + requestAnimationFrame(loop); + renderer.render(scene, camera); + } + loop(); +} + +// --- Initialize --- +document.addEventListener("DOMContentLoaded", () => { + const detectedPlatform = detectPlatform(); + switchPlatform(detectedPlatform); + + initScrollAnimations(); + initNoiseOverlay(); + + const terminalEl = document.getElementById("terminal-demo"); + + if (terminalEl) { + const demo = new TerminalDemo(terminalEl); + + const observer = new IntersectionObserver( + (entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + demo.start(); + } else { + demo.stop(); + } + }); + }, + { threshold: 0.3 }, + ); + + observer.observe(document.querySelector(".terminal-window")); + } + + const nav = document.querySelector(".nav"); + let ticking = false; + window.addEventListener("scroll", () => { + if (!ticking) { + requestAnimationFrame(() => { + if (window.scrollY > 50) { + nav.style.borderBottomColor = "rgba(48, 80, 255, 0.15)"; + } else { + nav.style.borderBottomColor = ""; + } + ticking = false; + }); + ticking = true; + } + }); +}); diff --git a/landingpage/style.css b/landingpage/style.css new file mode 100644 index 0000000000..30334df0d0 --- /dev/null +++ b/landingpage/style.css @@ -0,0 +1,1178 @@ +/* ========================================================================= + Hermes Agent Landing Page + Colors: Nous Blue (#3050FF) palette + ========================================================================= */ + +/* --- Reset & Base --- */ +*, *::before, *::after { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary: #3050FF; + --primary-light: #5070FF; + --primary-dim: #2040CC; + --primary-dark: #1E30AA; + --bg: #0A0E1A; + --bg-card: #12182A; + --bg-card-hover: #1A2240; + --border: rgba(48, 80, 255, 0.1); + --border-hover: rgba(48, 80, 255, 0.22); + --text: #E8ECFF; + --text-dim: #8090BB; + --text-muted: #506090; + --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace; + --container: 1080px; + --radius: 12px; + --radius-sm: 8px; + + --ease-in-quad: cubic-bezier(.55, .085, .68, .53); + --ease-in-cubic: cubic-bezier(.550, .055, .675, .19); + --ease-in-quart: cubic-bezier(.895, .03, .685, .22); + --ease-in-quint: cubic-bezier(.755, .05, .855, .06); + --ease-in-expo: cubic-bezier(.95, .05, .795, .035); + --ease-in-circ: cubic-bezier(.6, .04, .98, .335); + + --ease-out-quad: cubic-bezier(.25, .46, .45, .94); + --ease-out-cubic: cubic-bezier(.215, .61, .355, 1); + --ease-out-quart: cubic-bezier(.165, .84, .44, 1); + --ease-out-quint: cubic-bezier(.23, 1, .32, 1); + --ease-out-expo: cubic-bezier(.19, 1, .22, 1); + --ease-out-circ: cubic-bezier(.075, .82, .165, 1); + + --ease-in-out-quad: cubic-bezier(.455, .03, .515, .955); + --ease-in-out-cubic: cubic-bezier(.645, .045, .355, 1); + --ease-in-out-quart: cubic-bezier(.77, 0, .175, 1); + --ease-in-out-quint: cubic-bezier(.86, 0, .07, 1); + --ease-in-out-expo: cubic-bezier(1, 0, 0, 1); + --ease-in-out-circ: cubic-bezier(.785, .135, .15, .86); +} + +html { + scroll-behavior: smooth; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + overflow-x: hidden; +} + +body { + font-family: var(--font-sans); + background: var(--bg); + color: var(--text); + line-height: 1.6; + overflow-x: hidden; + width: 100%; + max-width: 100vw; + background-image: radial-gradient(rgba(48, 80, 255, 0.04) 1px, transparent 1px); + background-size: 32px 32px; +} + +a { + color: var(--primary); + text-decoration: none; + transition: color 0.2s var(--ease-out-quad); +} +a:hover { + color: var(--primary-light); +} + +strong { + color: #fff; + font-weight: 600; +} + +/* --- Noise Overlay --- */ +#noise-overlay { + position: fixed; + inset: 0; + width: 100%; + height: 100%; + z-index: 50; + pointer-events: none; + mix-blend-mode: soft-light; +} + +/* --- Ambient Glow --- */ +.ambient-glow { + position: fixed; + pointer-events: none; + z-index: 0; + border-radius: 50%; + filter: blur(120px); + opacity: 0.15; +} +.glow-1 { + width: 600px; + height: 600px; + background: var(--primary); + top: -200px; + left: -200px; + opacity: 0.08; +} +.glow-2 { + width: 500px; + height: 500px; + background: var(--primary-dim); + bottom: 20%; + right: -150px; + opacity: 0.06; +} + +/* --- Container --- */ +.container { + max-width: var(--container); + margin: 0 auto; + padding: 0 24px; +} + +/* --- Navigation --- */ +.nav { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 100; + background: rgba(7, 7, 13, 0.8); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-bottom: 1px solid var(--border); + transition: border-bottom-color 0.3s var(--ease-out-quad); +} + +.nav-inner { + max-width: var(--container); + margin: 0 auto; + padding: 0 24px; + height: 60px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.nav-logo { + display: flex; + align-items: center; + gap: 10px; + color: var(--text); + font-weight: 600; + font-size: 15px; + transition: color 0.2s var(--ease-out-quad); +} +.nav-logo:hover { color: var(--primary-light); } + +.nav-nous-logo { + width: 22px; + height: 22px; + border-radius: 4px; +} + +.nav-by { + font-weight: 400; + color: var(--text-muted); + font-size: 13px; +} + +.nav-links { + display: flex; + align-items: center; + gap: 28px; +} + +.nav-links a { + color: var(--text-dim); + font-size: 14px; + font-weight: 500; + display: flex; + align-items: center; + gap: 4px; + transition: color 0.2s var(--ease-out-quad); +} +.nav-links a:hover { color: #fff; } + +.external-icon { opacity: 0.4; } + +/* --- Hamburger & Mobile Nav --- */ +.nav-hamburger { + display: none; + background: none; + border: none; + cursor: pointer; + padding: 6px; + width: 34px; + height: 34px; + flex-direction: column; + justify-content: center; + gap: 5px; +} + +.hamburger-bar { + display: block; + width: 20px; + height: 2px; + background: var(--text-dim); + border-radius: 1px; + transition: transform 0.25s var(--ease-out-quint), opacity 0.2s var(--ease-out-quad); + transform-origin: center; +} + +.nav-hamburger.open .hamburger-bar:nth-child(1) { + transform: translateY(7px) rotate(45deg); +} + +.nav-hamburger.open .hamburger-bar:nth-child(2) { + opacity: 0; +} + +.nav-hamburger.open .hamburger-bar:nth-child(3) { + transform: translateY(-7px) rotate(-45deg); +} + +.nav-mobile { + display: none; +} + +.nav-mobile.open { + display: flex; + flex-direction: column; + position: absolute; + top: 60px; + left: 0; + right: 0; + background: rgba(7, 7, 13, 0.95); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-bottom: 1px solid var(--border); + padding: 16px 24px; + gap: 16px; +} + +.nav-mobile a { + color: var(--text-dim); + font-size: 15px; + font-weight: 500; + padding: 4px 0; + transition: color 0.2s var(--ease-out-quad); +} + +.nav-mobile a:hover { + color: #fff; +} + +/* --- Hero --- */ +.hero { + position: relative; + z-index: 1; + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + padding: 120px 24px 80px; + text-align: center; +} + +.hero-content { + max-width: 760px; +} + +.hero-badge { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 6px 16px; + background: rgba(48, 80, 255, 0.08); + border: 1px solid rgba(48, 80, 255, 0.18); + border-radius: 100px; + font-size: 13px; + color: var(--text-dim); + margin-bottom: 32px; + font-weight: 450; +} + +.badge-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--primary); + display: inline-block; + animation: pulse-dot 2s var(--ease-in-out-quad) infinite; +} + +@keyframes pulse-dot { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} + +.hero-ascii { + margin-bottom: 28px; + font-family: 'JetBrains Mono', monospace; + font-variant-ligatures: none; + font-size: clamp(4px, 0.95vw, 11px); + line-height: 1.15; + color: var(--primary-light); + text-align: center; + text-shadow: 0 0 20px rgba(48, 80, 255, 0.3); + opacity: 0.85; + transition: opacity 0.3s var(--ease-out-cubic); + overflow-x: auto; + white-space: pre; +} + +.hero-ascii:hover { + opacity: 1; +} + +.hero-title { + font-size: clamp(36px, 6vw, 56px); + font-weight: 700; + line-height: 1.15; + letter-spacing: -0.03em; + margin-bottom: 20px; + color: #fff; +} + +.hero-gradient { + background: linear-gradient(135deg, var(--primary), var(--primary-light), #90B0FF); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.hero-subtitle { + font-size: 17px; + line-height: 1.7; + color: var(--text-dim); + max-width: 620px; + margin: 0 auto 36px; +} + +.hero-install { + margin-bottom: 32px; +} + +/* --- Install Widget (hero tabbed installer) --- */ +.install-widget { + max-width: 740px; + margin: 0 auto; + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; + transition: border-color 0.3s var(--ease-out-quad); +} + +.install-widget:hover { + border-color: var(--border-hover); +} + +.install-widget-header { + display: flex; + align-items: center; + gap: 16px; + padding: 10px 16px; + background: rgba(255, 255, 255, 0.02); + border-bottom: 1px solid var(--border); +} + +.install-dots { + display: flex; + gap: 6px; + flex-shrink: 0; +} + +.install-dots .dot { + width: 10px; + height: 10px; + border-radius: 50%; +} + +.install-tabs { + display: flex; + gap: 4px; + flex-wrap: wrap; +} + +.install-tab { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 14px; + border: none; + border-radius: 6px; + font-family: var(--font-sans); + font-size: 12px; + font-weight: 500; + cursor: pointer; + transition: color 0.2s var(--ease-out-quad), background 0.2s var(--ease-out-quad); + background: transparent; + color: var(--text-muted); +} + +.install-tab:hover { + color: var(--text-dim); + background: rgba(255, 255, 255, 0.04); +} + +.install-tab.active { + background: rgba(48, 80, 255, 0.14); + color: var(--primary-light); +} + +.install-tab svg { + flex-shrink: 0; +} + +.install-widget-body { + display: flex; + align-items: center; + gap: 10px; + padding: 14px 16px; + font-family: var(--font-mono); + font-size: 13px; + color: var(--text); + overflow-x: auto; +} + +.install-prompt { + color: var(--primary-light); + font-weight: 600; + flex-shrink: 0; + opacity: 0.7; +} + +.install-widget-body code { + flex: 1; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + text-align: left; + transition: opacity 0.15s var(--ease-out-quad); +} + +/* --- Code block tabs (install step section) --- */ +.code-tabs { + display: flex; + gap: 2px; +} + +.code-tab { + padding: 3px 10px; + border: none; + border-radius: 4px; + font-family: var(--font-mono); + font-size: 11px; + font-weight: 500; + cursor: pointer; + transition: color 0.2s var(--ease-out-quad), background 0.2s var(--ease-out-quad); + background: transparent; + color: var(--text-muted); +} + +.code-tab:hover { + color: var(--text-dim); + background: rgba(255, 255, 255, 0.04); +} + +.code-tab.active { + background: rgba(48, 80, 255, 0.12); + color: var(--primary-light); +} + +.copy-btn { + flex-shrink: 0; + display: flex; + align-items: center; + gap: 6px; + background: none; + border: none; + color: var(--text-dim); + cursor: pointer; + padding: 4px 8px; + border-radius: 6px; + font-family: var(--font-sans); + font-size: 12px; + transition: color 0.2s var(--ease-out-quad), background 0.2s var(--ease-out-quad); +} +.copy-btn:hover { + color: var(--primary-light); + background: rgba(48, 80, 255, 0.1); +} +.copy-btn:active { + transform: scale(0.95); +} + +.install-note { + font-size: 13px; + color: var(--text-muted); + margin-top: 12px; +} + +.hero-links { + display: flex; + gap: 12px; + justify-content: center; + flex-wrap: wrap; +} + +.btn { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 11px 24px; + border-radius: var(--radius); + font-size: 14px; + font-weight: 550; + transition: background 0.25s var(--ease-out-quint), border-color 0.25s var(--ease-out-quad), color 0.2s var(--ease-out-quad), transform 0.25s var(--ease-out-quint); + border: 1px solid transparent; + will-change: transform; +} + +.btn-primary { + background: rgba(48, 80, 255, 0.12); + color: var(--primary-light); + border-color: rgba(48, 80, 255, 0.25); +} +.btn-primary:hover { + background: rgba(48, 80, 255, 0.22); + border-color: rgba(48, 80, 255, 0.4); + color: #fff; +} + +@media (hover: hover) and (pointer: fine) { + .btn-primary:hover { + transform: translateY(-1px); + } +} +.btn:active { + transform: scale(0.97); +} + +/* --- Sections --- */ +.section { + position: relative; + z-index: 1; + padding: 80px 0; +} + +.section-header { + display: flex; + align-items: center; + justify-content: center; + gap: 12px; + margin-bottom: 48px; +} + +.section-header h2 { + font-size: 28px; + font-weight: 650; + color: #fff; + letter-spacing: -0.02em; +} + +.section-desc { + color: var(--text-dim); + font-size: 16px; + line-height: 1.7; + max-width: 640px; + margin: 0 auto 40px; + text-align: center; +} + +/* --- Features Grid --- */ +.features-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 16px; +} + +.feature-card { + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 20px; + transition: border-color 0.3s var(--ease-out-quad), background 0.3s var(--ease-out-quad), transform 0.3s var(--ease-out-quint); + will-change: transform; +} + +.feature-card:hover { + border-color: var(--border-hover); + background: var(--bg-card-hover); +} + +@media (hover: hover) and (pointer: fine) { + .feature-card:hover { + transform: translateY(-2px); + } +} + +.feature-header { + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; +} + +.feature-icon { + color: var(--primary-light); + opacity: 0.85; + flex-shrink: 0; + display: flex; + line-height: 0; +} + +.feature-card h3 { + font-size: 15px; + font-weight: 600; + color: #fff; + letter-spacing: -0.01em; +} + +.feature-card p { + font-size: 14px; + color: var(--text-dim); + line-height: 1.65; +} + +/* --- Terminal Demo --- */ +.section-demo { + padding-bottom: 60px; + border-top: 1px solid var(--border); + border-bottom: 1px solid var(--border); +} + +.terminal-window { + background: #0c0c14; + border: 1px solid var(--border); + border-radius: var(--radius); + overflow: hidden; + max-width: 800px; + margin: 0 auto; +} + +.terminal-header { + display: flex; + align-items: center; + padding: 12px 16px; + background: rgba(255, 255, 255, 0.02); + border-bottom: 1px solid var(--border); + gap: 12px; +} + +.terminal-dots { + display: flex; + gap: 6px; +} + +.dot { + width: 10px; + height: 10px; + border-radius: 50%; +} +.dot-red { background: #ff5f57; } +.dot-yellow { background: #febc2e; } +.dot-green { background: #28c840; } + +.terminal-title { + font-family: var(--font-mono); + font-size: 12px; + color: var(--text-muted); +} + +.terminal-body { + padding: 20px 24px; + height: 340px; + font-family: var(--font-mono); + font-size: 13px; + line-height: 1.7; + white-space: pre-wrap; + overflow-y: auto; + overflow-x: hidden; +} + +.terminal-cursor { + animation: blink 1s step-end infinite; + color: var(--primary-light); + opacity: 0.8; +} + +@keyframes blink { + 0%, 100% { opacity: 0.8; } + 50% { opacity: 0; } +} + +/* Terminal demo colors */ +.t-prompt { color: var(--primary-light); } +.t-cmd { color: #fff; } +.t-dim { color: var(--text-muted); } +.t-text { color: var(--text-dim); } +.t-green { color: #4ade80; } +.t-blue { color: #60a5fa; } +.t-accent { color: var(--primary-light); } +.t-highlight { color: #90B0FF; } +.t-tool { color: var(--text-muted); } + +/* --- Specs Toggle --- */ +.features-more { + text-align: center; + margin-top: 32px; +} + +.more-toggle { + background: none; + border: 1px solid var(--border); + color: var(--text-dim); + font-size: 14px; + font-family: inherit; + padding: 8px 20px; + border-radius: 6px; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 6px; + transition: color 0.2s var(--ease-out-quad), border-color 0.2s var(--ease-out-quad); +} + +.more-toggle:hover { + color: var(--primary-light); + border-color: var(--primary-light); +} +.more-toggle:active { + transform: scale(0.97); +} + +.more-chevron { + transition: transform 0.3s var(--ease-in-out-cubic); +} + +.more-toggle.open .more-chevron { + transform: rotate(180deg); +} + +.specs-wrapper { + max-height: 0; + overflow: hidden; + transition: max-height 0.4s var(--ease-out-quart), opacity 0.3s var(--ease-out-quad); + opacity: 0; +} + +.specs-wrapper.open { + opacity: 1; +} + +/* --- Specs --- */ +.section-specs { +} + +.specs-list { + max-width: 720px; + margin: 0 auto; + padding-top: 24px; +} + +.spec-row { + display: grid; + grid-template-columns: 120px 1fr; + gap: 24px; + padding: 24px 0; + border-bottom: 1px solid var(--border); +} + +.spec-row:last-child { + border-bottom: none; +} + +.spec-label { + font-size: 14px; + font-weight: 600; + color: var(--primary-light); + padding-top: 2px; +} + +.spec-value { + font-size: 15px; + color: var(--text-dim); + line-height: 1.7; +} + +.spec-value a { + color: var(--text); + border-bottom: 1px solid var(--border-hover); + transition: border-color 0.2s var(--ease-out-quad), color 0.2s var(--ease-out-quad); +} + +.spec-value a:hover { + color: var(--primary-light); + border-color: var(--primary-light); +} + +/* --- Install Section --- */ +.section-install { + border-top: 1px solid var(--border); +} + +.install-steps { + display: grid; + gap: 28px; + max-width: 640px; + margin: 0 auto; +} + +.install-step { + display: flex; + gap: 20px; +} + +.step-number { + flex-shrink: 0; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + background: rgba(48, 80, 255, 0.1); + border: 1px solid rgba(48, 80, 255, 0.2); + border-radius: 50%; + font-size: 14px; + font-weight: 600; + color: var(--primary-light); + margin-top: 2px; +} + +.step-content { + flex: 1; + min-width: 0; +} + +.step-content h4 { + font-size: 16px; + font-weight: 600; + color: #fff; + margin-bottom: 10px; +} + +.step-optional { + font-size: 12px; + font-weight: 400; + color: var(--text-muted); +} + +.step-note { + font-size: 13px; + color: var(--text-muted); + margin-top: 8px; +} + +.code-block { + background: #0c0c14; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + overflow: hidden; +} + +.code-block-sm { + max-width: 640px; +} + +.code-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 14px; + background: rgba(255, 255, 255, 0.02); + border-bottom: 1px solid var(--border); + font-family: var(--font-mono); + font-size: 11px; + color: var(--text-muted); +} + +.code-block pre { + padding: 14px 16px; + font-family: var(--font-mono); + font-size: 13px; + line-height: 1.6; + color: var(--text); + overflow-x: auto; + white-space: pre-wrap; + word-break: break-all; +} + +.code-comment { + color: var(--text-muted); +} + +.install-windows { + margin-top: 48px; + padding-top: 32px; + border-top: 1px solid var(--border); + max-width: 640px; + margin-left: auto; + margin-right: auto; +} + +.install-windows p { + font-size: 14px; + color: var(--text-dim); + margin-bottom: 12px; +} + +/* --- Footer --- */ +.footer { + position: relative; + z-index: 1; + padding: 40px 0 32px; + border-top: 1px solid var(--border); +} + +.footer-copy { + text-align: center; + font-size: 13px; + color: var(--text-muted); +} + +.footer-copy a { + color: var(--text-dim); + transition: color 0.2s var(--ease-out-quad); +} + +.footer-copy a:hover { + color: var(--primary-light); +} + +/* --- Scroll Animations --- */ +.fade-in { + opacity: 0; + transform: translateY(20px); + transition: opacity 0.6s var(--ease-out-quart), transform 0.6s var(--ease-out-quart); + will-change: transform, opacity; +} + +.fade-in.visible { + opacity: 1; + transform: translateY(0); +} + +/* --- Responsive --- */ + +/* Clamp ambient glows so they can't cause horizontal scroll */ +@media (max-width: 900px) { + .ambient-glow { display: none; } + + .features-grid { + grid-template-columns: repeat(2, 1fr); + } + +} + +@media (max-width: 640px) { + /* --- Global mobile --- */ + .container { + padding: 0 16px; + } + + .section { + padding: 50px 0; + } + + .section-header { + margin-bottom: 32px; + } + + .section-header h2 { + font-size: 20px; + } + + .section-desc { + font-size: 14px; + } + + /* --- Nav --- */ + .nav-inner { + padding: 0 16px; + } + + .nav-links { + display: none; + } + + .nav-hamburger { + display: flex; + } + + /* --- Hero --- */ + .hero { + padding: 90px 16px 50px; + min-height: auto; + } + + .hero-content { + max-width: 100%; + } + + .hero-badge { + font-size: 11px; + padding: 5px 12px; + margin-bottom: 24px; + } + + .hero-ascii { + font-size: 3.5px; + } + + .hero-title { + font-size: 26px; + margin-bottom: 14px; + } + + .hero-subtitle { + font-size: 14px; + line-height: 1.6; + margin: 0 auto 28px; + } + + .install-widget-body { + font-size: 10px; + padding: 10px 12px; + } + + .install-widget-body code { + overflow: hidden; + text-overflow: ellipsis; + display: block; + } + + .install-widget-header { + padding: 8px 12px; + gap: 10px; + } + + .install-tabs { + gap: 2px; + } + + .install-tab { + padding: 4px 10px; + font-size: 11px; + } + + .install-tab svg { + display: none; + } + + .copy-btn { + padding: 3px 6px; + } + + .copy-btn .copy-text { display: none; } + + .install-note { + font-size: 11px; + } + + .hero-links { + flex-direction: column; + align-items: stretch; + } + + .hero-links .btn { + justify-content: center; + } + + /* --- Grids → single column --- */ + .features-grid { + grid-template-columns: 1fr; + } + + .spec-row { + grid-template-columns: 1fr; + gap: 6px; + padding: 18px 0; + } + + .feature-card { + padding: 16px 18px; + } + + .feature-card p { + font-size: 13px; + line-height: 1.5; + } + + /* --- Terminal demo --- */ + .terminal-body { + font-size: 11px; + padding: 14px; + height: 260px; + } + + /* --- Install steps --- */ + .install-steps { + max-width: 100%; + } + + .install-step { + gap: 14px; + } + + .step-number { + width: 28px; + height: 28px; + font-size: 13px; + } + + .code-block pre { + font-size: 11px; + word-break: break-all; + } + + .install-windows { + max-width: 100%; + } + + /* --- Footer --- */ + .footer { + padding: 32px 0 24px; + } + +} + +/* --- Reduced Motion --- */ +@media (prefers-reduced-motion: reduce) { + *, *::before, *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .fade-in { + opacity: 1; + transform: none; + } + + .hero-ascii { + opacity: 0.85; + } +} + +/* --- Selection --- */ +::selection { + background: rgba(48, 80, 255, 0.25); + color: #fff; +} + +/* --- Scrollbar --- */ +::-webkit-scrollbar { + width: 6px; + height: 6px; +} +::-webkit-scrollbar-track { + background: var(--bg); +} +::-webkit-scrollbar-thumb { + background: var(--border-hover); + border-radius: 3px; +} +::-webkit-scrollbar-thumb:hover { + background: var(--primary-dim); +}