1188 lines
33 KiB
HTML
1188 lines
33 KiB
HTML
<!doctype html>
|
||
<html lang="ru">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>spacesh — терминал-воркспейс для AI-агентов на macOS</title>
|
||
<meta name="description" content="Запускай Claude Code, Codex, Gemini и shell параллельно. Фоновый демон держит сессии живыми: закрыл окно — агенты работают. Скачать для macOS.">
|
||
<link rel="canonical" href="https://spaceshell.ru">
|
||
<meta property="og:title" content="spacesh — терминал-воркспейс для AI-агентов">
|
||
<meta property="og:description" content="Десяток AI-агентов параллельно. Демон держит сессии живыми — закрой окно, агенты работают.">
|
||
<meta property="og:url" content="https://spaceshell.ru">
|
||
<meta property="og:image" content="https://spaceshell.ru/og.png">
|
||
<meta property="og:type" content="website">
|
||
<meta name="theme-color" content="#0A0D12">
|
||
|
||
<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=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||
|
||
<style>
|
||
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||
|
||
:root {
|
||
--bg-base: #0A0D12;
|
||
--bg-panel: #0E1116;
|
||
--bg-elevated: #11161F;
|
||
--border-subtle: #232A33;
|
||
--border-strong: #323C49;
|
||
--text-primary: #E6EDF3;
|
||
--text-secondary: #8B97A6;
|
||
--text-muted: #5A6573;
|
||
--accent-primary: #34D3C2;
|
||
--accent-secondary: #4F9CF9;
|
||
--status-work: #4C8DFF;
|
||
--status-wait: #F2B84B;
|
||
--status-done: #3FB950;
|
||
--status-error: #F4544E;
|
||
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
|
||
--font-body: 'Inter', -apple-system, system-ui, sans-serif;
|
||
--radius-sm: 8px;
|
||
--radius-md: 12px;
|
||
--radius-lg: 14px;
|
||
}
|
||
|
||
html { scroll-behavior: smooth; }
|
||
|
||
body {
|
||
font-family: var(--font-body);
|
||
background: var(--bg-base);
|
||
color: var(--text-primary);
|
||
line-height: 1.6;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* Scanlines texture */
|
||
body::before {
|
||
content: '';
|
||
position: fixed;
|
||
inset: 0;
|
||
background: repeating-linear-gradient(
|
||
0deg,
|
||
transparent,
|
||
transparent 2px,
|
||
rgba(255,255,255,0.008) 2px,
|
||
rgba(255,255,255,0.008) 4px
|
||
);
|
||
pointer-events: none;
|
||
z-index: 9999;
|
||
}
|
||
|
||
a { color: inherit; text-decoration: none; }
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
padding: 0 24px;
|
||
}
|
||
|
||
/* Header */
|
||
.header {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 100;
|
||
padding: 16px 0;
|
||
transition: background 0.3s, backdrop-filter 0.3s;
|
||
}
|
||
|
||
.header.scrolled {
|
||
background: rgba(10, 13, 18, 0.85);
|
||
backdrop-filter: blur(12px);
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.header-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 32px;
|
||
}
|
||
|
||
.logo {
|
||
font-family: var(--font-mono);
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.logo-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
background: var(--bg-elevated);
|
||
border: 1px solid var(--border-strong);
|
||
border-radius: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
color: var(--accent-primary);
|
||
}
|
||
|
||
.nav {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 32px;
|
||
}
|
||
|
||
.nav a {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.nav a:hover { color: var(--text-primary); }
|
||
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 10px 20px;
|
||
border-radius: var(--radius-sm);
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.2s;
|
||
}
|
||
|
||
.btn-primary {
|
||
background: var(--accent-primary);
|
||
color: var(--bg-base);
|
||
}
|
||
|
||
.btn-primary:hover {
|
||
background: #45e0d0;
|
||
box-shadow: 0 0 24px rgba(52, 211, 194, 0.3);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: transparent;
|
||
color: var(--text-secondary);
|
||
border: 1px solid var(--border-strong);
|
||
}
|
||
|
||
.btn-secondary:hover {
|
||
border-color: var(--text-secondary);
|
||
color: var(--text-primary);
|
||
}
|
||
|
||
.btn-large {
|
||
padding: 14px 28px;
|
||
font-size: 16px;
|
||
}
|
||
|
||
/* Hero */
|
||
.hero {
|
||
min-height: 100vh;
|
||
padding: 140px 0 80px;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.hero-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 64px;
|
||
align-items: center;
|
||
}
|
||
|
||
.hero-eyebrow {
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.hero-title {
|
||
font-family: var(--font-mono);
|
||
font-size: clamp(32px, 4vw, 48px);
|
||
font-weight: 700;
|
||
line-height: 1.2;
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.hero-title .accent { color: var(--accent-primary); }
|
||
|
||
.hero-subtitle {
|
||
font-size: 18px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.7;
|
||
margin-bottom: 32px;
|
||
max-width: 520px;
|
||
}
|
||
|
||
.hero-buttons {
|
||
display: flex;
|
||
gap: 16px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.hero-meta {
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.hero-meta span {
|
||
margin: 0 8px;
|
||
opacity: 0.5;
|
||
}
|
||
|
||
/* Terminal mockup */
|
||
.terminal-mockup {
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-lg);
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
.terminal-header {
|
||
background: var(--bg-elevated);
|
||
padding: 12px 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.terminal-dots {
|
||
display: flex;
|
||
gap: 6px;
|
||
}
|
||
|
||
.terminal-dot {
|
||
width: 12px;
|
||
height: 12px;
|
||
border-radius: 50%;
|
||
background: var(--border-strong);
|
||
}
|
||
|
||
.terminal-title {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.terminal-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1px;
|
||
background: var(--border-subtle);
|
||
}
|
||
|
||
.terminal-pane {
|
||
background: var(--bg-base);
|
||
padding: 16px;
|
||
min-height: 140px;
|
||
position: relative;
|
||
}
|
||
|
||
.pane-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.pane-name {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--text-muted);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.status-ring {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
animation: pulse 2s infinite;
|
||
}
|
||
|
||
.status-work { background: var(--status-work); box-shadow: 0 0 8px var(--status-work); }
|
||
.status-wait { background: var(--status-wait); box-shadow: 0 0 8px var(--status-wait); }
|
||
.status-done { background: var(--status-done); box-shadow: 0 0 8px var(--status-done); }
|
||
.status-idle { background: var(--text-muted); }
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { opacity: 1; }
|
||
50% { opacity: 0.5; }
|
||
}
|
||
|
||
.pane-content {
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.pane-content .typed-line {
|
||
overflow: hidden;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.cursor {
|
||
display: inline-block;
|
||
width: 8px;
|
||
height: 14px;
|
||
background: var(--accent-primary);
|
||
animation: blink 1s step-end infinite;
|
||
vertical-align: text-bottom;
|
||
margin-left: 2px;
|
||
}
|
||
|
||
@keyframes blink {
|
||
0%, 50% { opacity: 1; }
|
||
51%, 100% { opacity: 0; }
|
||
}
|
||
|
||
.daemon-badge {
|
||
position: absolute;
|
||
bottom: 12px;
|
||
right: 12px;
|
||
background: var(--bg-elevated);
|
||
border: 1px solid var(--status-done);
|
||
border-radius: 4px;
|
||
padding: 4px 8px;
|
||
font-family: var(--font-mono);
|
||
font-size: 10px;
|
||
color: var(--status-done);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
|
||
.daemon-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: var(--status-done);
|
||
animation: pulse 1.5s infinite;
|
||
}
|
||
|
||
/* Agents strip */
|
||
.agents-strip {
|
||
padding: 48px 0;
|
||
border-top: 1px solid var(--border-subtle);
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.agents-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.agents-label {
|
||
font-size: 14px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.agent-tag {
|
||
font-family: var(--font-mono);
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
padding: 8px 14px;
|
||
border-radius: var(--radius-sm);
|
||
}
|
||
|
||
/* Problem/Solution */
|
||
.problem-section {
|
||
padding: 100px 0;
|
||
}
|
||
|
||
.problem-grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 48px;
|
||
}
|
||
|
||
.problem-card, .solution-card {
|
||
padding: 32px;
|
||
border-radius: var(--radius-md);
|
||
}
|
||
|
||
.problem-card {
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.solution-card {
|
||
background: linear-gradient(135deg, rgba(52, 211, 194, 0.08), rgba(79, 156, 249, 0.08));
|
||
border: 1px solid rgba(52, 211, 194, 0.2);
|
||
}
|
||
|
||
.card-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.problem-card .card-label { color: var(--status-error); }
|
||
.solution-card .card-label { color: var(--accent-primary); }
|
||
|
||
.card-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.card-text {
|
||
color: var(--text-secondary);
|
||
line-height: 1.7;
|
||
}
|
||
|
||
/* Features */
|
||
.features-section {
|
||
padding: 100px 0;
|
||
}
|
||
|
||
.section-header {
|
||
text-align: center;
|
||
margin-bottom: 64px;
|
||
}
|
||
|
||
.section-title {
|
||
font-family: var(--font-mono);
|
||
font-size: clamp(28px, 3vw, 36px);
|
||
font-weight: 600;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-size: 18px;
|
||
color: var(--text-secondary);
|
||
max-width: 600px;
|
||
margin: 0 auto;
|
||
}
|
||
|
||
.features-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 24px;
|
||
}
|
||
|
||
.feature-card {
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-md);
|
||
padding: 28px;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.feature-card:hover {
|
||
border-color: var(--border-strong);
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 0 32px rgba(52, 211, 194, 0.08);
|
||
}
|
||
|
||
.feature-icon {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
color: var(--accent-primary);
|
||
background: rgba(52, 211, 194, 0.1);
|
||
padding: 6px 10px;
|
||
border-radius: 4px;
|
||
display: inline-block;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.feature-title {
|
||
font-family: var(--font-mono);
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.feature-text {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.7;
|
||
}
|
||
|
||
/* How it works */
|
||
.how-section {
|
||
padding: 100px 0;
|
||
background: var(--bg-panel);
|
||
border-top: 1px solid var(--border-subtle);
|
||
border-bottom: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.steps-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 48px;
|
||
}
|
||
|
||
.step {
|
||
text-align: center;
|
||
}
|
||
|
||
.step-number {
|
||
font-family: var(--font-mono);
|
||
font-size: 48px;
|
||
font-weight: 700;
|
||
color: var(--border-strong);
|
||
margin-bottom: 24px;
|
||
}
|
||
|
||
.step-title {
|
||
font-family: var(--font-mono);
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.step-text {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
line-height: 1.7;
|
||
}
|
||
|
||
.step-diagram {
|
||
margin-top: 16px;
|
||
font-family: var(--font-mono);
|
||
font-size: 11px;
|
||
color: var(--text-muted);
|
||
background: var(--bg-base);
|
||
padding: 12px;
|
||
border-radius: var(--radius-sm);
|
||
border: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
/* Roadmap */
|
||
.roadmap-section {
|
||
padding: 80px 0;
|
||
}
|
||
|
||
.roadmap-inner {
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
border-radius: var(--radius-md);
|
||
padding: 32px;
|
||
}
|
||
|
||
.roadmap-label {
|
||
font-family: var(--font-mono);
|
||
font-size: 12px;
|
||
color: var(--status-wait);
|
||
text-transform: uppercase;
|
||
letter-spacing: 0.05em;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.roadmap-title {
|
||
font-size: 20px;
|
||
font-weight: 600;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.roadmap-items {
|
||
display: flex;
|
||
gap: 24px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.roadmap-item {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
}
|
||
|
||
.roadmap-dot {
|
||
width: 6px;
|
||
height: 6px;
|
||
border-radius: 50%;
|
||
background: var(--status-wait);
|
||
}
|
||
|
||
/* Tech strip */
|
||
.tech-strip {
|
||
padding: 64px 0;
|
||
border-top: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.tech-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 48px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.tech-item {
|
||
font-family: var(--font-mono);
|
||
font-size: 14px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.tech-highlight {
|
||
background: var(--bg-panel);
|
||
border: 1px solid var(--border-subtle);
|
||
padding: 12px 20px;
|
||
border-radius: var(--radius-sm);
|
||
color: var(--text-secondary);
|
||
}
|
||
|
||
/* Final CTA */
|
||
.cta-section {
|
||
padding: 120px 0;
|
||
text-align: center;
|
||
}
|
||
|
||
.cta-title {
|
||
font-family: var(--font-mono);
|
||
font-size: clamp(24px, 3vw, 32px);
|
||
font-weight: 600;
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.cta-buttons {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 16px;
|
||
margin-bottom: 32px;
|
||
}
|
||
|
||
.cta-github {
|
||
font-size: 14px;
|
||
color: var(--text-secondary);
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.cta-github:hover { color: var(--accent-primary); }
|
||
|
||
/* Footer */
|
||
.footer {
|
||
padding: 48px 0;
|
||
border-top: 1px solid var(--border-subtle);
|
||
}
|
||
|
||
.footer-inner {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
flex-wrap: wrap;
|
||
gap: 24px;
|
||
}
|
||
|
||
.footer-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24px;
|
||
}
|
||
|
||
.footer-logo {
|
||
font-family: var(--font-mono);
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.footer-copy {
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
.footer-links {
|
||
display: flex;
|
||
gap: 24px;
|
||
}
|
||
|
||
.footer-links a {
|
||
font-size: 13px;
|
||
color: var(--text-secondary);
|
||
transition: color 0.2s;
|
||
}
|
||
|
||
.footer-links a:hover { color: var(--text-primary); }
|
||
|
||
.footer-tagline {
|
||
font-size: 13px;
|
||
color: var(--text-muted);
|
||
font-style: italic;
|
||
}
|
||
|
||
/* Mobile nav */
|
||
.mobile-nav-toggle {
|
||
display: none;
|
||
background: none;
|
||
border: none;
|
||
color: var(--text-primary);
|
||
font-size: 24px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
/* Responsive */
|
||
@media (max-width: 1024px) {
|
||
.hero-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 48px;
|
||
}
|
||
|
||
.features-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
}
|
||
|
||
.steps-grid {
|
||
grid-template-columns: 1fr;
|
||
gap: 32px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.nav { display: none; }
|
||
.mobile-nav-toggle { display: block; }
|
||
|
||
.hero { padding: 120px 0 60px; }
|
||
|
||
.hero-buttons {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.problem-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.features-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.terminal-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.tech-inner {
|
||
gap: 24px;
|
||
}
|
||
|
||
.footer-inner {
|
||
flex-direction: column;
|
||
text-align: center;
|
||
}
|
||
|
||
.footer-left {
|
||
flex-direction: column;
|
||
}
|
||
}
|
||
|
||
/* Reduced motion */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
|
||
/* Scroll reveal */
|
||
.reveal {
|
||
opacity: 0;
|
||
transform: translateY(20px);
|
||
transition: opacity 0.6s, transform 0.6s;
|
||
}
|
||
|
||
.reveal.visible {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<!-- Header -->
|
||
<header class="header" id="header">
|
||
<div class="container">
|
||
<div class="header-inner">
|
||
<a href="/" class="logo">
|
||
<span class="logo-icon">>_</span>
|
||
spacesh
|
||
</a>
|
||
<nav class="nav">
|
||
<a href="#features">Возможности</a>
|
||
<a href="#how">Как работает</a>
|
||
<a href="#cli">CLI</a>
|
||
<a href="https://git.realmanual.ru/realmanual/spaceshell" target="_blank" rel="noopener">GitHub</a>
|
||
</nav>
|
||
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary">Скачать для macOS</a>
|
||
<button class="mobile-nav-toggle" aria-label="Меню">☰</button>
|
||
</div>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- Hero -->
|
||
<section class="hero">
|
||
<div class="container">
|
||
<div class="hero-grid">
|
||
<div class="hero-content">
|
||
<p class="hero-eyebrow">Терминал-воркспейс для AI-агентов · macOS</p>
|
||
<h1 class="hero-title">
|
||
Гоняй десяток AI-агентов параллельно. <span class="accent">Не теряй ни одного.</span>
|
||
</h1>
|
||
<p class="hero-subtitle">
|
||
spacesh держит живые сессии Claude Code, Codex, Gemini и shell в фоновом демоне.
|
||
Закрыл окно, обновил приложение, словил краш — агенты продолжают работать.
|
||
</p>
|
||
<div class="hero-buttons">
|
||
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary btn-large">
|
||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
||
</svg>
|
||
Скачать для macOS
|
||
</a>
|
||
<a href="#how" class="btn btn-secondary btn-large">Как это работает</a>
|
||
</div>
|
||
<p class="hero-meta">
|
||
macOS 13+ <span>·</span> Apple Silicon и Intel <span>·</span> открытый исходник <span>·</span> early access
|
||
</p>
|
||
</div>
|
||
|
||
<div class="terminal-mockup">
|
||
<div class="terminal-header">
|
||
<div class="terminal-dots">
|
||
<span class="terminal-dot"></span>
|
||
<span class="terminal-dot"></span>
|
||
<span class="terminal-dot"></span>
|
||
</div>
|
||
<span class="terminal-title">spacesh — workspace</span>
|
||
</div>
|
||
<div class="terminal-grid">
|
||
<div class="terminal-pane">
|
||
<div class="pane-header">
|
||
<span class="pane-name">
|
||
<span class="status-ring status-work"></span>
|
||
claude-code
|
||
</span>
|
||
</div>
|
||
<div class="pane-content">
|
||
<div class="typed-line" id="typed1"></div>
|
||
</div>
|
||
</div>
|
||
<div class="terminal-pane">
|
||
<div class="pane-header">
|
||
<span class="pane-name">
|
||
<span class="status-ring status-done"></span>
|
||
codex
|
||
</span>
|
||
</div>
|
||
<div class="pane-content">
|
||
<span style="color: var(--status-done);">✓</span> Refactored auth module<br>
|
||
<span style="color: var(--text-muted);">3 files changed</span>
|
||
</div>
|
||
</div>
|
||
<div class="terminal-pane">
|
||
<div class="pane-header">
|
||
<span class="pane-name">
|
||
<span class="status-ring status-wait"></span>
|
||
gemini
|
||
</span>
|
||
</div>
|
||
<div class="pane-content">
|
||
<span style="color: var(--status-wait);">⏳</span> Waiting for API...<br>
|
||
<span style="color: var(--text-muted);">rate limit cooldown</span>
|
||
</div>
|
||
</div>
|
||
<div class="terminal-pane">
|
||
<div class="pane-header">
|
||
<span class="pane-name">
|
||
<span class="status-ring status-idle"></span>
|
||
shell
|
||
</span>
|
||
</div>
|
||
<div class="pane-content">
|
||
<span style="color: var(--text-muted);">~/projects/app $</span> <span class="cursor"></span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="daemon-badge">
|
||
<span class="daemon-dot"></span>
|
||
daemon · alive
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Agents strip -->
|
||
<section class="agents-strip">
|
||
<div class="container">
|
||
<div class="agents-inner">
|
||
<span class="agents-label">Работает с:</span>
|
||
<span class="agent-tag">Claude Code</span>
|
||
<span class="agent-tag">Codex</span>
|
||
<span class="agent-tag">Gemini</span>
|
||
<span class="agent-tag">opencode</span>
|
||
<span class="agent-tag">shell</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Problem/Solution -->
|
||
<section class="problem-section">
|
||
<div class="container">
|
||
<div class="problem-grid reveal">
|
||
<div class="problem-card">
|
||
<p class="card-label">Проблема</p>
|
||
<h3 class="card-title">Обычный терминал привязывает агента к окну.</h3>
|
||
<p class="card-text">
|
||
Закрыл вкладку, перезапустил приложение, упал GUI — длинная сессия агента умирает вместе с ним.
|
||
</p>
|
||
</div>
|
||
<div class="solution-card">
|
||
<p class="card-label">Решение</p>
|
||
<h3 class="card-title">spacesh разрывает эту связь.</h3>
|
||
<p class="card-text">
|
||
Сессиями владеет фоновый демон, а не окно. Интерфейс — всего лишь вид поверх него.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Features -->
|
||
<section class="features-section" id="features">
|
||
<div class="container">
|
||
<div class="section-header reveal">
|
||
<h2 class="section-title">Возможности</h2>
|
||
</div>
|
||
<div class="features-grid">
|
||
<div class="feature-card reveal">
|
||
<span class="feature-icon">daemon</span>
|
||
<h3 class="feature-title">Демон — источник истины</h3>
|
||
<p class="feature-text">
|
||
spaceshd владеет живыми PTY-сессиями. GUI и CLI — тонкие клиенты поверх одного Unix-сокета.
|
||
Убей интерфейс — агент жив. Открой заново — экран восстановится из снапшота за доли секунды.
|
||
</p>
|
||
</div>
|
||
<div class="feature-card reveal">
|
||
<span class="feature-icon">grid</span>
|
||
<h3 class="feature-title">Параллельные агенты в одной сетке</h3>
|
||
<p class="feature-text">
|
||
Несколько агентов в раскладке-гриде: сплиты, зум панели, перетаскивание, пресеты (2×2, 1+2, 2×3…),
|
||
воркспейсы и избранное.
|
||
</p>
|
||
</div>
|
||
<div class="feature-card reveal">
|
||
<span class="feature-icon">status</span>
|
||
<h3 class="feature-title">Статусы без догадок</h3>
|
||
<p class="feature-text">
|
||
work · wait · done · error · idle приходят пушем — от хуков агентов, маркеров OSC 133 и паттернов.
|
||
Кольца, бейджи, центр событий и нативные уведомления macOS.
|
||
</p>
|
||
</div>
|
||
<div class="feature-card reveal" id="cli">
|
||
<span class="feature-icon">search</span>
|
||
<h3 class="feature-title">Гибридный терминал</h3>
|
||
<p class="feature-text">
|
||
xterm.js рисует, грид alacritty в демоне анализирует. Отсюда — поиск по скроллбэку (⌘F) с подсветкой,
|
||
извлечение последней команды и мгновенные снапшоты для reattach.
|
||
</p>
|
||
</div>
|
||
<div class="feature-card reveal">
|
||
<span class="feature-icon">cli</span>
|
||
<h3 class="feature-title">CLI как первый класс</h3>
|
||
<p class="feature-text">
|
||
spacesh status --json, focus, new-surface, notify — те же команды, что и в интерфейсе, плюс shell-completions.
|
||
Встраивай spacesh в свои пайплайны.
|
||
</p>
|
||
</div>
|
||
<div class="feature-card reveal">
|
||
<span class="feature-icon">theme</span>
|
||
<h3 class="feature-title">Под себя</h3>
|
||
<p class="feature-text">
|
||
Тёмная и светлая темы, акцентные цвета, шрифт и размер терминала, дефолтный shell —
|
||
всё хранится демоном в config.toml и применяется на лету ко всем окнам.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- How it works -->
|
||
<section class="how-section" id="how">
|
||
<div class="container">
|
||
<div class="section-header reveal">
|
||
<h2 class="section-title">Как это работает</h2>
|
||
</div>
|
||
<div class="steps-grid">
|
||
<div class="step reveal">
|
||
<div class="step-number">01</div>
|
||
<h3 class="step-title">Запуск</h3>
|
||
<p class="step-text">
|
||
Создаёшь воркспейс и панели — демон спавнит PTY-сессии под агентов.
|
||
</p>
|
||
<div class="step-diagram">
|
||
spawn → spaceshd → PTY
|
||
</div>
|
||
</div>
|
||
<div class="step reveal">
|
||
<div class="step-number">02</div>
|
||
<h3 class="step-title">Демон владеет</h3>
|
||
<p class="step-text">
|
||
Байты летают GUI ↔ демон ↔ PTY по одному сокету. Интерфейс состояния не хранит — только команды и события.
|
||
</p>
|
||
<div class="step-diagram">
|
||
GUI ⇄ Unix socket ⇄ PTY
|
||
</div>
|
||
</div>
|
||
<div class="step reveal">
|
||
<div class="step-number">03</div>
|
||
<h3 class="step-title">Reattach</h3>
|
||
<p class="step-text">
|
||
Закрыл и открыл приложение — демон отдаёт снапшот экрана, окно перерисовывается мгновенно.
|
||
</p>
|
||
<div class="step-diagram">
|
||
snapshot → restore → live
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Roadmap -->
|
||
<section class="roadmap-section">
|
||
<div class="container">
|
||
<div class="roadmap-inner reveal">
|
||
<p class="roadmap-label">В планах</p>
|
||
<h3 class="roadmap-title">Над чем работаем</h3>
|
||
<div class="roadmap-items">
|
||
<span class="roadmap-item">
|
||
<span class="roadmap-dot"></span>
|
||
Внешние уведомления в Telegram и MAX
|
||
</span>
|
||
<span class="roadmap-item">
|
||
<span class="roadmap-dot"></span>
|
||
diff-просмотр изменений агента
|
||
</span>
|
||
<span class="roadmap-item">
|
||
<span class="roadmap-dot"></span>
|
||
Удалённая работа через SSH-туннель к демону
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Tech strip -->
|
||
<section class="tech-strip">
|
||
<div class="container">
|
||
<div class="tech-inner">
|
||
<span class="tech-item">Rust</span>
|
||
<span class="tech-item">Tauri 2</span>
|
||
<span class="tech-item">tokio</span>
|
||
<span class="tech-item">xterm.js</span>
|
||
<span class="tech-item">alacritty</span>
|
||
<span class="tech-highlight">< 16 мс на нажатие клавиши</span>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Final CTA -->
|
||
<section class="cta-section" id="download">
|
||
<div class="container">
|
||
<h2 class="cta-title reveal">Готов гонять агентов пачками?</h2>
|
||
<div class="cta-buttons reveal">
|
||
<a href="https://spaceshell.ru/download/spacesh.dmg" download class="btn btn-primary btn-large">
|
||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||
<path d="M8 0a8 8 0 100 16A8 8 0 008 0zm3.5 9l-3 3a.7.7 0 01-1 0l-3-3a.7.7 0 011-1L7 9.5V4a1 1 0 012 0v5.5L10.5 8a.7.7 0 011 1z"/>
|
||
</svg>
|
||
Скачать для macOS
|
||
</a>
|
||
</div>
|
||
<a href="https://git.realmanual.ru/realmanual/spaceshell" target="_blank" rel="noopener" class="cta-github">
|
||
Исходники на GitHub →
|
||
</a>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- Footer -->
|
||
<footer class="footer">
|
||
<div class="container">
|
||
<div class="footer-inner">
|
||
<div class="footer-left">
|
||
<span class="footer-logo">spaceshell.ru</span>
|
||
<span class="footer-copy">© 2026 spacesh</span>
|
||
</div>
|
||
<div class="footer-links">
|
||
<a href="https://git.realmanual.ru/realmanual/spaceshell" target="_blank" rel="noopener">GitHub</a>
|
||
<a href="#">Документация</a>
|
||
<a href="#">Лицензия</a>
|
||
</div>
|
||
<p class="footer-tagline">Сделано для тех, кто запускает агентов пачками.</p>
|
||
</div>
|
||
</div>
|
||
</footer>
|
||
|
||
<script>
|
||
// Header scroll effect
|
||
const header = document.getElementById('header');
|
||
window.addEventListener('scroll', () => {
|
||
header.classList.toggle('scrolled', window.scrollY > 50);
|
||
});
|
||
|
||
// Scroll reveal
|
||
const reveals = document.querySelectorAll('.reveal');
|
||
const revealObserver = new IntersectionObserver((entries) => {
|
||
entries.forEach(entry => {
|
||
if (entry.isIntersecting) {
|
||
entry.target.classList.add('visible');
|
||
}
|
||
});
|
||
}, { threshold: 0.1 });
|
||
|
||
reveals.forEach(el => revealObserver.observe(el));
|
||
|
||
// Typewriter effect
|
||
const typedEl = document.getElementById('typed1');
|
||
const lines = [
|
||
'Analyzing codebase structure...',
|
||
'Found 47 components',
|
||
'Refactoring payment module...',
|
||
'✓ Updated PaymentService.ts',
|
||
'Running tests...'
|
||
];
|
||
let lineIndex = 0;
|
||
let charIndex = 0;
|
||
|
||
function type() {
|
||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||
typedEl.innerHTML = lines[0] + '<span class="cursor"></span>';
|
||
return;
|
||
}
|
||
|
||
const currentLine = lines[lineIndex];
|
||
|
||
if (charIndex < currentLine.length) {
|
||
typedEl.innerHTML = currentLine.substring(0, charIndex + 1) + '<span class="cursor"></span>';
|
||
charIndex++;
|
||
setTimeout(type, 30 + Math.random() * 40);
|
||
} else {
|
||
setTimeout(() => {
|
||
charIndex = 0;
|
||
lineIndex = (lineIndex + 1) % lines.length;
|
||
typedEl.innerHTML = '<span class="cursor"></span>';
|
||
setTimeout(type, 500);
|
||
}, 2000);
|
||
}
|
||
}
|
||
|
||
type();
|
||
</script>
|
||
</body>
|
||
</html> |