Updated styles

This commit is contained in:
Timmy
2026-04-03 21:03:54 +01:00
parent 5594c6d21e
commit dc0c2a75df
4 changed files with 457 additions and 122 deletions
+8 -3
View File
@@ -577,9 +577,14 @@ async fn main() -> Result<(), std::io::Error> {
let host = std::env::var("HUSKIES_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
let addr = format!("{host}:{port}");
println!(
"\x1b[95;1m ____ _ _ ___ _ \n / ___|| |_ ___ _ __| | _|_ _| |_ \n \\___ \\| __/ _ \\| '__| |/ /| || __|\n ___) | || (_) | | | < | || |_ \n |____/ \\__\\___/|_| |_|\\_\\___|\\__|\n\x1b[0m"
);
println!("\x1b[96;1m");
println!(" ╱▔▔╲ \x1b[97;1m _ _ _ _ \x1b[96;1m");
println!(" ( ◕ ◕) \x1b[97;1m| | | |_ _ ___| | _(_) ___ ___\x1b[96;1m");
println!(" ╲ ▽ \x1b[97;1m| |_| | | | / __| |/ / |/ _ \\/ __|\x1b[96;1m");
println!(" /| |\\ \x1b[97;1m| _ | |_| \\__ \\ <| | __/\\__ \\\x1b[96;1m");
println!(" / | | \\\x1b[97;1m|_| |_|\\__,_|___/_|\\_\\_|\\___||___/\x1b[96;1m");
println!(" ╱╱ ╲╲ \x1b[90mStory-driven development, powered by AI\x1b[0m");
println!();
println!("HUSKIES_PORT={port}");
println!("\x1b[96;1mFrontend:\x1b[0m \x1b[94mhttp://{addr}\x1b[0m");
println!("\x1b[92;1mOpenAPI Docs:\x1b[0m \x1b[94mhttp://{addr}/docs\x1b[0m");
+34
View File
@@ -0,0 +1,34 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
<!-- Husky head - geometric/angular style -->
<!-- Ears -->
<path d="M60 85 L45 35 L85 65 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
<path d="M140 85 L155 35 L115 65 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
<!-- Inner ears -->
<path d="M62 78 L52 45 L80 65 Z" fill="#4a5568"/>
<path d="M138 78 L148 45 L120 65 Z" fill="#4a5568"/>
<!-- Head shape -->
<path d="M55 80 Q55 60 75 60 L125 60 Q145 60 145 80 L145 120 Q145 155 120 165 L110 170 Q100 175 90 170 L80 165 Q55 155 55 120 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
<!-- Face mask (white marking) -->
<path d="M75 70 L100 65 L125 70 L120 110 L110 135 Q100 142 90 135 L80 110 Z" fill="#e8ecf4"/>
<!-- Forehead stripe -->
<path d="M92 65 L100 62 L108 65 L104 95 L100 100 L96 95 Z" fill="#8892a8"/>
<!-- Eyes -->
<ellipse cx="82" cy="95" rx="7" ry="7.5" fill="#080c15"/>
<ellipse cx="118" cy="95" rx="7" ry="7.5" fill="#080c15"/>
<!-- Eye shine - cyan to match brand -->
<circle cx="80" cy="93" r="2.5" fill="#22d3ee"/>
<circle cx="116" cy="93" r="2.5" fill="#22d3ee"/>
<!-- Iris detail -->
<ellipse cx="82" cy="95" rx="4" ry="4.5" fill="none" stroke="#22d3ee" stroke-width="0.5" opacity="0.4"/>
<ellipse cx="118" cy="95" rx="4" ry="4.5" fill="none" stroke="#22d3ee" stroke-width="0.5" opacity="0.4"/>
<!-- Nose -->
<path d="M95 120 Q100 115 105 120 Q105 126 100 128 Q95 126 95 120 Z" fill="#080c15"/>
<!-- Nose highlight -->
<ellipse cx="100" cy="120" rx="2" ry="1" fill="#4a5568"/>
<!-- Mouth -->
<path d="M100 128 L100 135" stroke="#4a5568" stroke-width="1.5" stroke-linecap="round"/>
<path d="M92 138 Q100 143 108 138" stroke="#4a5568" stroke-width="1.5" fill="none" stroke-linecap="round"/>
<!-- Cheek fur tufts -->
<path d="M55 105 Q48 110 50 120" stroke="#e8ecf4" stroke-width="1" fill="none" opacity="0.5"/>
<path d="M145 105 Q152 110 150 120" stroke="#e8ecf4" stroke-width="1" fill="none" opacity="0.5"/>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+109 -30
View File
@@ -5,63 +5,142 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Huskies — Story-Driven Development for AI Agents</title>
<meta name="description" content="Huskies is an autonomous development pipeline that turns user stories into tested, shipped code using AI agents.">
<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=Bricolage+Grotesque:wght@400;500;600;700;800&family=Karla:ital,wght@0,300;0,400;0,500;1,300;1,400&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="page">
<header>
<h1>husk<span>ies</span></h1>
<p class="tagline">Story-driven development, powered by AI agents.</p>
<!-- Nav -->
<header class="reveal r1">
<a href="/" class="logo">huskies</a>
<nav>
<a href="#how">How it works</a>
<a href="#features">Features</a>
<a href="mailto:hello@huskies.dev" class="nav-cta">Get in touch</a>
</nav>
</header>
<section>
<h2>What is Huskies?</h2>
<p>Huskies is an autonomous development pipeline that turns user stories into tested, shipped code. You describe what you want. AI agents handle the rest &mdash; implementation, testing, code review, and merge.</p>
<p>Talk to it from your IDE, a chat room, or WhatsApp. Stories flow through a structured pipeline: backlog, current, QA, merge, done.</p>
<!-- Hero -->
<section class="hero">
<div class="hero-graphic reveal r1">
<img src="husky.svg" alt="" class="hero-husky">
</div>
<p class="hero-kicker reveal r1">Story-driven development</p>
<h1 class="reveal r2">You describe it.<br>Agents <span class="glow">ship it.</span></h1>
<p class="hero-sub reveal r3">An autonomous development pipeline that turns user stories into tested, merged code. AI agents handle implementation, testing, and deployment &mdash; you keep the final say.</p>
<!-- Pipeline viz -->
<div class="pipeline reveal r4">
<div class="pipe-stage">
<span class="pipe-dot"></span>
<span class="pipe-label">Story</span>
</div>
<span class="pipe-line"></span>
<div class="pipe-stage">
<span class="pipe-dot active"></span>
<span class="pipe-label">Implement</span>
</div>
<span class="pipe-line"></span>
<div class="pipe-stage">
<span class="pipe-dot"></span>
<span class="pipe-label">QA</span>
</div>
<span class="pipe-line"></span>
<div class="pipe-stage">
<span class="pipe-dot"></span>
<span class="pipe-label">Merge</span>
</div>
<span class="pipe-line"></span>
<div class="pipe-stage">
<span class="pipe-dot done"></span>
<span class="pipe-label">Done</span>
</div>
</div>
</section>
<section>
<h2>How it works</h2>
<!-- How it works -->
<section id="how" class="how-section">
<h2 class="section-title reveal r5">How it works</h2>
<ol class="steps">
<li>You write a user story with acceptance criteria.</li>
<li>An AI agent picks it up, creates a feature branch, and implements the code.</li>
<li>A QA agent runs tests, linters, and quality gates automatically.</li>
<li>A merge agent resolves conflicts and lands it on your main branch.</li>
<li>You review the result. Accept or send it back.</li>
<li class="step reveal r5">
<span class="step-num">01</span>
<div class="step-body">
<h3>Write a story</h3>
<p>Describe what you want with acceptance criteria. From your IDE, a chat room, or WhatsApp.</p>
</div>
</li>
<li class="step reveal r5">
<span class="step-num">02</span>
<div class="step-body">
<h3>Agent picks it up</h3>
<p>A coder agent creates a feature branch, implements the code, and writes tests against your criteria.</p>
</div>
</li>
<li class="step reveal r6">
<span class="step-num">03</span>
<div class="step-body">
<h3>Quality gates run</h3>
<p>Linters, tests, and compilation checks run automatically. Nothing moves forward until everything passes.</p>
</div>
</li>
<li class="step reveal r6">
<span class="step-num">04</span>
<div class="step-body">
<h3>Merge &amp; land</h3>
<p>A merge agent resolves conflicts and squash-merges to your main branch. You review and accept.</p>
</div>
</li>
</ol>
</section>
<section>
<h2>Features</h2>
<div class="features">
<div class="feature">
<h3>Story-Driven Workflow</h3>
<p>Stories define the change. Tests define the truth. Code defines the reality. No code ships without acceptance criteria.</p>
<!-- Features -->
<section id="features" class="features-section">
<h2 class="section-title reveal r7">Features</h2>
<div class="feature-grid">
<div class="feature reveal r7">
<div class="feature-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/></svg>
</div>
<h3>Story-Driven Workflow</h3>
<p>Stories define the change. Tests define the truth. Code defines the reality. Nothing ships without acceptance criteria.</p>
</div>
<div class="feature reveal r7">
<div class="feature-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98"/></svg>
</div>
<div class="feature">
<h3>Multi-Agent Pipeline</h3>
<p>Coder, QA, and merge agents work in parallel across isolated git worktrees. Configure agent count, models, and budgets.</p>
</div>
<div class="feature">
<div class="feature reveal r8">
<div class="feature-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>
</div>
<h3>Chat Anywhere</h3>
<p>Control the pipeline from Matrix, WhatsApp, Slack, or the built-in web UI. Create stories, start agents, check status.</p>
</div>
<div class="feature">
<h3>Full Autonomy, Your Oversight</h3>
<div class="feature reveal r8">
<div class="feature-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
</div>
<h3>Your Oversight</h3>
<p>Agents implement, test, and merge independently. You approve what ships. Every story is traceable from request to release.</p>
</div>
</div>
</section>
<section>
<h2>Get in touch</h2>
<p>Huskies is built by <a href="https://crashlabs.io">Crashlabs</a>. Interested in early access or have questions? Reach out at <a href="mailto:hello@huskies.dev">hello@huskies.dev</a>.</p>
<!-- CTA -->
<section class="cta-section reveal r8">
<h2>Interested?</h2>
<p>Huskies is built by <a href="https://crashlabs.io">Crash Labs</a>. Get in touch at <a href="mailto:hello@huskies.dev">hello@huskies.dev</a>.</p>
</section>
<footer>
<p>&copy; 2026 Libby Labs Ltd. All rights reserved. &middot; <a href="privacy.html">Privacy Policy</a></p>
<footer class="reveal r8">
<span>&copy; 2026 Libby Labs Ltd.</span>
<a href="privacy.html">Privacy Policy</a>
</footer>
</div>
+307 -90
View File
@@ -1,140 +1,357 @@
:root {
--bg: #0a0a0a;
--fg: #e8e8e8;
--muted: #888;
--accent: #4f9cf7;
--surface: #141414;
--border: #222;
--max-w: 720px;
--bg: #080c15;
--surface: #0e1420;
--surface-hover: #131a28;
--border: #1a2235;
--text: #e8ecf4;
--text-secondary: #8892a8;
--text-dim: #4a5568;
--cyan: #22d3ee;
--cyan-dim: rgba(34, 211, 238, 0.07);
--cyan-glow: rgba(34, 211, 238, 0.15);
--display: 'Bricolage Grotesque', sans-serif;
--body: 'Karla', sans-serif;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
font-family: var(--body);
background: var(--bg);
color: var(--fg);
color: var(--text);
line-height: 1.6;
min-height: 100vh;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
a { color: var(--cyan); text-decoration: none; transition: opacity 0.2s; }
a:hover { opacity: 0.7; }
.container {
max-width: var(--max-w);
/* Animations */
@keyframes fadeUp {
from { opacity: 0; transform: translateY(18px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes pulse {
0%, 100% { box-shadow: 0 0 0 0 var(--cyan-glow); }
50% { box-shadow: 0 0 12px 4px var(--cyan-glow); }
}
.reveal {
opacity: 0;
animation: fadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.r1 { animation-delay: 0.05s; }
.r2 { animation-delay: 0.15s; }
.r3 { animation-delay: 0.3s; }
.r4 { animation-delay: 0.5s; }
.r5 { animation-delay: 0.65s; }
.r6 { animation-delay: 0.8s; }
.r7 { animation-delay: 0.95s; }
.r8 { animation-delay: 1.1s; }
/* Layout */
.page {
max-width: 960px;
margin: 0 auto;
padding: 0 24px;
padding: 0 3rem;
}
/* ── Header ── */
@media (max-width: 640px) {
.page { padding: 0 1.5rem; }
}
/* Header */
header {
padding: 48px 0 32px;
border-bottom: 1px solid var(--border);
padding: 2rem 0;
display: flex;
justify-content: space-between;
align-items: center;
}
header h1 {
font-size: 2rem;
font-weight: 700;
letter-spacing: -0.03em;
}
header h1 span { color: var(--accent); }
header p.tagline {
color: var(--muted);
.logo {
font-family: var(--display);
font-size: 1.1rem;
margin-top: 8px;
font-weight: 800;
letter-spacing: -0.03em;
color: var(--text) !important;
}
/* ── Sections ── */
section {
padding: 48px 0;
border-bottom: 1px solid var(--border);
header nav {
display: flex;
align-items: center;
gap: 2rem;
}
section:last-of-type { border-bottom: none; }
header nav a {
font-size: 0.82rem;
color: var(--text-dim);
}
section h2 {
font-size: 1.25rem;
header nav a:hover { color: var(--text); opacity: 1; }
.nav-cta {
color: var(--cyan) !important;
font-weight: 500;
}
/* Hero */
.hero {
padding: 10vh 0 6vh;
text-align: center;
}
.hero-graphic {
margin-bottom: 2.5rem;
}
.hero-husky {
width: 120px;
height: 120px;
filter: drop-shadow(0 0 20px rgba(34, 211, 238, 0.1));
}
.hero-kicker {
font-family: var(--display);
font-size: 0.7rem;
font-weight: 600;
margin-bottom: 16px;
letter-spacing: -0.02em;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--cyan);
margin-bottom: 2rem;
}
section p { color: var(--muted); margin-bottom: 12px; }
.hero h1 {
font-family: var(--display);
font-size: clamp(2.5rem, 6vw, 4.2rem);
font-weight: 800;
line-height: 1.1;
letter-spacing: -0.03em;
margin-bottom: 1.8rem;
max-width: 700px;
margin-left: auto;
margin-right: auto;
}
/* ── Feature grid ── */
.features {
.glow {
color: var(--cyan);
text-shadow: 0 0 30px var(--cyan-glow);
}
.hero-sub {
font-size: 1.05rem;
font-weight: 300;
color: var(--text-secondary);
line-height: 1.8;
max-width: 520px;
margin: 0 auto;
}
/* Pipeline visualisation */
.pipeline {
display: flex;
align-items: center;
justify-content: center;
gap: 0;
margin-top: 4rem;
padding: 2rem 0;
}
.pipe-stage {
display: flex;
flex-direction: column;
align-items: center;
gap: 0.8rem;
}
.pipe-dot {
width: 12px;
height: 12px;
border-radius: 50%;
border: 2px solid var(--border);
background: var(--surface);
transition: all 0.3s;
}
.pipe-dot.active {
border-color: var(--cyan);
background: var(--cyan);
animation: pulse 2s ease-in-out infinite;
}
.pipe-dot.done {
border-color: var(--text-dim);
background: var(--text-dim);
}
.pipe-label {
font-family: var(--display);
font-size: 0.65rem;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--text-dim);
}
.pipe-stage:has(.active) .pipe-label {
color: var(--cyan);
}
.pipe-line {
width: 60px;
height: 1px;
background: var(--border);
margin: 0 0.5rem;
margin-bottom: 2rem;
}
@media (max-width: 500px) {
.pipe-line { width: 30px; }
.pipe-label { font-size: 0.55rem; }
}
/* Sections */
.section-title {
font-family: var(--display);
font-size: 1.6rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 2.5rem;
}
/* How it works */
.how-section {
padding: 5rem 0;
border-top: 1px solid var(--border);
}
.steps {
list-style: none;
display: flex;
flex-direction: column;
gap: 0;
}
.step {
display: grid;
grid-template-columns: 56px 1fr;
gap: 1.5rem;
padding: 1.8rem 0;
border-bottom: 1px solid var(--border);
align-items: start;
}
.step:first-child {
border-top: 1px solid var(--border);
}
.step-num {
font-family: var(--display);
font-size: 0.75rem;
font-weight: 700;
color: var(--text-dim);
padding-top: 0.15rem;
}
.step-body h3 {
font-family: var(--display);
font-size: 1rem;
font-weight: 600;
margin-bottom: 0.4rem;
}
.step-body p {
font-size: 0.88rem;
font-weight: 300;
color: var(--text-secondary);
line-height: 1.7;
}
/* Features */
.features-section {
padding: 5rem 0;
border-top: 1px solid var(--border);
}
.feature-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-top: 16px;
gap: 1px;
background: var(--border);
border: 1px solid var(--border);
}
.feature {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 8px;
padding: 20px;
padding: 2rem;
transition: background 0.3s;
}
.feature:hover {
background: var(--surface-hover);
}
.feature-icon {
color: var(--cyan);
margin-bottom: 1.2rem;
opacity: 0.8;
}
.feature h3 {
font-family: var(--display);
font-size: 0.95rem;
font-weight: 600;
margin-bottom: 6px;
margin-bottom: 0.5rem;
}
.feature p {
font-size: 0.875rem;
color: var(--muted);
margin: 0;
font-size: 0.82rem;
font-weight: 300;
color: var(--text-secondary);
line-height: 1.7;
}
/* ── How it works ── */
.steps {
list-style: none;
counter-reset: step;
margin-top: 16px;
@media (max-width: 600px) {
.feature-grid { grid-template-columns: 1fr; }
}
.steps li {
counter-increment: step;
padding: 12px 0;
padding-left: 36px;
position: relative;
color: var(--muted);
font-size: 0.95rem;
}
.steps li::before {
content: counter(step);
position: absolute;
left: 0;
top: 12px;
width: 24px;
height: 24px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 50%;
font-size: 0.75rem;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
color: var(--accent);
}
/* ── Footer ── */
footer {
padding: 32px 0;
color: var(--muted);
font-size: 0.8rem;
/* CTA */
.cta-section {
padding: 5rem 0;
border-top: 1px solid var(--border);
text-align: center;
}
/* ── Responsive ── */
@media (max-width: 540px) {
.features { grid-template-columns: 1fr; }
header h1 { font-size: 1.5rem; }
.cta-section h2 {
font-family: var(--display);
font-size: 1.8rem;
font-weight: 700;
letter-spacing: -0.02em;
margin-bottom: 1rem;
}
.cta-section p {
font-size: 0.95rem;
color: var(--text-secondary);
font-weight: 300;
}
/* Footer */
footer {
padding: 2rem 0;
border-top: 1px solid var(--border);
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.75rem;
color: var(--text-dim);
}
footer a {
color: var(--text-dim);
font-size: 0.75rem;
}
footer a:hover { color: var(--text-secondary); }