diff --git a/src/commands/init.rs b/src/commands/init.rs
index f2786368..de7b575b 100644
--- a/src/commands/init.rs
+++ b/src/commands/init.rs
@@ -40,7 +40,7 @@ ignore:
hook:
mode: warn # "warn" (print but allow) or "block" (fail commit)
min_severity: major # minimum severity to trigger hook action
- max_diff_size: 50000 # max diff chars before refusing
+ max_diff_size: 5242880 # max 5MB diff chars before refusing
# Output settings
output:
diff --git a/website/components.json b/website/components.json
new file mode 100644
index 00000000..86d24fd1
--- /dev/null
+++ b/website/components.json
@@ -0,0 +1,16 @@
+{
+ "$schema": "https://shadcn-svelte.com/schema.json",
+ "style": "vega",
+ "tailwind": {
+ "config": "tailwind.config.js",
+ "css": "src/app.css",
+ "baseColor": "zinc"
+ },
+ "aliases": {
+ "components": "$lib/components",
+ "utils": "$lib/utils",
+ "ui": "$lib/components/ui",
+ "hooks": "$lib/hooks"
+ },
+ "typescript": true
+}
diff --git a/website/package-lock.json b/website/package-lock.json
index 760f1319..86b81b06 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -8,13 +8,19 @@
"name": "cora-website",
"version": "0.0.1",
"devDependencies": {
+ "@internationalized/date": "^3.12.2",
+ "@lucide/svelte": "^1.17.0",
"@sveltejs/adapter-auto": "^7.0.1",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.57.0",
"@sveltejs/vite-plugin-svelte": "^7.0.0",
"@tailwindcss/vite": "^4.3.0",
+ "bits-ui": "^2.18.1",
+ "clsx": "^2.1.1",
"svelte": "^5.55.2",
"svelte-check": "^4.4.6",
+ "tailwind-merge": "^3.6.0",
+ "tailwind-variants": "^3.2.2",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.2",
"vite": "^8.0.7"
@@ -51,6 +57,40 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@floating-ui/core": {
+ "version": "1.7.5",
+ "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz",
+ "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==",
+ "dev": true,
+ "dependencies": {
+ "@floating-ui/utils": "^0.2.11"
+ }
+ },
+ "node_modules/@floating-ui/dom": {
+ "version": "1.7.6",
+ "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz",
+ "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==",
+ "dev": true,
+ "dependencies": {
+ "@floating-ui/core": "^1.7.5",
+ "@floating-ui/utils": "^0.2.11"
+ }
+ },
+ "node_modules/@floating-ui/utils": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz",
+ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==",
+ "dev": true
+ },
+ "node_modules/@internationalized/date": {
+ "version": "3.12.2",
+ "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.12.2.tgz",
+ "integrity": "sha512-FY1Y+H64NDs+HAF6omlnWxm3mEpfgaCSWtL5l551ZZfImA+kGjPFgrnJrGjH6lfmLL0g8Z/mBu1R3kufeCp6Jw==",
+ "dev": true,
+ "dependencies": {
+ "@swc/helpers": "^0.5.0"
+ }
+ },
"node_modules/@jridgewell/gen-mapping": {
"version": "0.3.13",
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
@@ -96,6 +136,15 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@lucide/svelte": {
+ "version": "1.17.0",
+ "resolved": "https://registry.npmjs.org/@lucide/svelte/-/svelte-1.17.0.tgz",
+ "integrity": "sha512-q06YCFBN5CO8cd1ADmLCxWRVMVb7xxvHzqC0lvNoxGa+FLW6Cd1Y1AOxgbQk4Iwe68vkAMCRveNHint4WoaVKg==",
+ "dev": true,
+ "peerDependencies": {
+ "svelte": "^5"
+ }
+ },
"node_modules/@napi-rs/wasm-runtime": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz",
@@ -470,6 +519,15 @@
"vite": "^8.0.0-beta.7 || ^8.0.0"
}
},
+ "node_modules/@swc/helpers": {
+ "version": "0.5.23",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz",
+ "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==",
+ "dev": true,
+ "dependencies": {
+ "tslib": "^2.8.0"
+ }
+ },
"node_modules/@tailwindcss/node": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.0.tgz",
@@ -785,6 +843,30 @@
"node": ">= 0.4"
}
},
+ "node_modules/bits-ui": {
+ "version": "2.18.1",
+ "resolved": "https://registry.npmjs.org/bits-ui/-/bits-ui-2.18.1.tgz",
+ "integrity": "sha512-KkemzKFH4T3gt3H+P86JcnAWExjByv/6vlwjm/BoCwTPHu03yiCdxbghdJLvFReQTe0acCAiRcKfmixxD6XvlA==",
+ "dev": true,
+ "dependencies": {
+ "@floating-ui/core": "^1.7.1",
+ "@floating-ui/dom": "^1.7.1",
+ "esm-env": "^1.1.2",
+ "runed": "^0.35.1",
+ "svelte-toolbelt": "^0.10.6",
+ "tabbable": "^6.2.0"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/huntabyte"
+ },
+ "peerDependencies": {
+ "@internationalized/date": "^3.8.1",
+ "svelte": "^5.33.0"
+ }
+ },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -827,6 +909,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/dequal": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
+ "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/detect-libc": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
@@ -915,6 +1006,12 @@
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
"dev": true
},
+ "node_modules/inline-style-parser": {
+ "version": "0.2.7",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.7.tgz",
+ "integrity": "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==",
+ "dev": true
+ },
"node_modules/is-reference": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
@@ -1197,6 +1294,15 @@
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
"dev": true
},
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "dev": true,
+ "bin": {
+ "lz-string": "bin/bin.js"
+ }
+ },
"node_modules/magic-string": {
"version": "0.30.21",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
@@ -1344,6 +1450,30 @@
"@rolldown/binding-win32-x64-msvc": "1.0.2"
}
},
+ "node_modules/runed": {
+ "version": "0.35.1",
+ "resolved": "https://registry.npmjs.org/runed/-/runed-0.35.1.tgz",
+ "integrity": "sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/huntabyte",
+ "https://github.com/sponsors/tglide"
+ ],
+ "dependencies": {
+ "dequal": "^2.0.3",
+ "esm-env": "^1.0.0",
+ "lz-string": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@sveltejs/kit": "^2.21.0",
+ "svelte": "^5.7.0"
+ },
+ "peerDependenciesMeta": {
+ "@sveltejs/kit": {
+ "optional": true
+ }
+ }
+ },
"node_modules/sade": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
@@ -1385,6 +1515,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/style-to-object": {
+ "version": "1.0.14",
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.14.tgz",
+ "integrity": "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==",
+ "dev": true,
+ "dependencies": {
+ "inline-style-parser": "0.2.7"
+ }
+ },
"node_modules/svelte": {
"version": "5.56.0",
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.56.0.tgz",
@@ -1435,6 +1574,62 @@
"typescript": ">=5.0.0"
}
},
+ "node_modules/svelte-toolbelt": {
+ "version": "0.10.6",
+ "resolved": "https://registry.npmjs.org/svelte-toolbelt/-/svelte-toolbelt-0.10.6.tgz",
+ "integrity": "sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/huntabyte"
+ ],
+ "dependencies": {
+ "clsx": "^2.1.1",
+ "runed": "^0.35.1",
+ "style-to-object": "^1.0.8"
+ },
+ "engines": {
+ "node": ">=18",
+ "pnpm": ">=8.7.0"
+ },
+ "peerDependencies": {
+ "svelte": "^5.30.2"
+ }
+ },
+ "node_modules/tabbable": {
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz",
+ "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==",
+ "dev": true
+ },
+ "node_modules/tailwind-merge": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.6.0.tgz",
+ "integrity": "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==",
+ "dev": true,
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/dcastil"
+ }
+ },
+ "node_modules/tailwind-variants": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-3.2.2.tgz",
+ "integrity": "sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==",
+ "dev": true,
+ "engines": {
+ "node": ">=16.x",
+ "pnpm": ">=7.x"
+ },
+ "peerDependencies": {
+ "tailwind-merge": ">=3.0.0",
+ "tailwindcss": "*"
+ },
+ "peerDependenciesMeta": {
+ "tailwind-merge": {
+ "optional": true
+ }
+ }
+ },
"node_modules/tailwindcss": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.0.tgz",
@@ -1483,8 +1678,7 @@
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
- "dev": true,
- "optional": true
+ "dev": true
},
"node_modules/typescript": {
"version": "6.0.3",
diff --git a/website/package.json b/website/package.json
index 57997c5e..1f25c94f 100644
--- a/website/package.json
+++ b/website/package.json
@@ -11,13 +11,19 @@
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json"
},
"devDependencies": {
+ "@internationalized/date": "^3.12.2",
+ "@lucide/svelte": "^1.17.0",
"@sveltejs/adapter-auto": "^7.0.1",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.57.0",
"@sveltejs/vite-plugin-svelte": "^7.0.0",
"@tailwindcss/vite": "^4.3.0",
+ "bits-ui": "^2.18.1",
+ "clsx": "^2.1.1",
"svelte": "^5.55.2",
"svelte-check": "^4.4.6",
+ "tailwind-merge": "^3.6.0",
+ "tailwind-variants": "^3.2.2",
"tailwindcss": "^4.3.0",
"typescript": "^6.0.2",
"vite": "^8.0.7"
diff --git a/website/src/app.css b/website/src/app.css
index d0b315da..dc5be977 100644
--- a/website/src/app.css
+++ b/website/src/app.css
@@ -113,6 +113,61 @@ code, .font-mono {
.animate-fade-in-delay-4 { animation: fade-in-up 0.6s ease-out 0.4s forwards; opacity: 0; }
.cursor-blink { animation: blink 1s step-end infinite; }
+
+ /* Hero entrance cascade */
+ .animate-fade-in-up {
+ opacity: 0;
+ transform: translateY(20px);
+ animation: fade-in-up 0.6s ease-out forwards;
+ }
+ .delay-100 { animation-delay: 100ms; }
+ .delay-200 { animation-delay: 200ms; }
+ .delay-300 { animation-delay: 300ms; }
+ .delay-400 { animation-delay: 400ms; }
+ .delay-500 { animation-delay: 500ms; }
+
+ /* Scroll Reveal — hidden until IntersectionObserver adds .revealed */
+ .scroll-reveal {
+ opacity: 0;
+ transform: translateY(20px);
+ transition: opacity 0.6s ease-out, transform 0.6s ease-out;
+ }
+.scroll-reveal.revealed {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Terminal typing line-by-line fade-in */
+@keyframes fade-in-line {
+ from { opacity: 0; transform: translateX(-8px); }
+ to { opacity: 1; transform: translateX(0); }
+}
+
+/* Timeline number pulse */
+@keyframes number-pulse {
+ 0%, 100% { box-shadow: 0 0 0 0 oklch(0.65 0.22 270 / 0.4); }
+ 50% { box-shadow: 0 0 0 8px oklch(0.65 0.22 270 / 0); }
+}
+
+.timeline-number.revealed {
+ animation: number-pulse 2s ease-in-out 1 forwards;
+}
+
+/* Comparison table row stagger */
+.compare-table tbody tr {
+ opacity: 0;
+ transform: translateY(8px);
+ transition: opacity 0.4s ease-out, transform 0.4s ease-out;
+}
+.compare-table tbody tr.revealed {
+ opacity: 1;
+ transform: translateY(0);
+}
+
+/* Smooth scrolling */
+html {
+ scroll-behavior: smooth;
+}
}
@media (prefers-reduced-motion: reduce) {
@@ -121,8 +176,9 @@ code, .font-mono {
transition-duration: 0.01ms !important;
}
html { scroll-behavior: auto; }
- .animate-fade-in, .animate-fade-in-delay-1, .animate-fade-in-delay-2,
- .animate-fade-in-delay-3, .animate-fade-in-delay-4 { opacity: 1 !important; }
+ .animate-fade-in, .animate-fade-in-up, .animate-fade-in-delay-1, .animate-fade-in-delay-2,
+ .animate-fade-in-delay-3, .animate-fade-in-delay-4,
+ .scroll-reveal { opacity: 1 !important; transform: none !important; }
}
/* ============================================
@@ -150,6 +206,161 @@ code, .font-mono {
background-size: 64px 64px;
}
+/* ============================================
+ SECTION LAYOUTS
+ ============================================ */
+.section {
+ width: 100%;
+ max-width: 1152px;
+ margin-left: auto;
+ margin-right: auto;
+ padding-left: var(--space-6);
+ padding-right: var(--space-6);
+}
+@media (min-width: 768px) {
+ .section { padding-left: var(--space-8); padding-right: var(--space-8); }
+}
+@media (min-width: 1280px) {
+ .section { padding-left: var(--space-10); padding-right: var(--space-10); }
+}
+
+.section-hero {
+ padding-top: var(--space-24);
+ padding-bottom: var(--space-16);
+}
+
+.section-compact {
+ padding-top: var(--space-16);
+ padding-bottom: var(--space-16);
+}
+
+.section-tall {
+ padding-top: var(--space-24);
+ padding-bottom: var(--space-24);
+}
+
+/* ============================================
+ GLASS CARD
+ ============================================ */
+.glass-card {
+ background: oklch(0.17 0.01 270 / 0.6);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ border: 1px solid oklch(0.27 0.01 270 / 0.5);
+ border-radius: var(--space-4);
+ transition: border-color 200ms ease-out, box-shadow 200ms ease-out;
+}
+.glass-card:hover {
+ border-color: oklch(0.65 0.22 270 / 0.3);
+ box-shadow: 0 0 24px oklch(0.65 0.22 270 / 0.08);
+}
+
+/* ============================================
+ FEATURE ICON
+ ============================================ */
+.feature-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: var(--space-10);
+ height: var(--space-10);
+ border-radius: var(--space-3);
+ background: oklch(0.65 0.22 270 / 0.1);
+ color: var(--accent);
+ flex-shrink: 0;
+}
+
+/* ============================================
+ CONNECT LINE (architecture flow)
+ ============================================ */
+.connect-line {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: var(--space-1) 0;
+}
+.connect-line::before {
+ content: '';
+ display: block;
+ width: 1px;
+ height: var(--space-4);
+ background: oklch(0.65 0.22 270 / 0.3);
+}
+
+/* ============================================
+ BUTTONS (landing page)
+ ============================================ */
+.btn-primary {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--space-2);
+ background: var(--accent);
+ color: var(--accent-foreground);
+ border-radius: var(--space-2);
+ padding: var(--space-2) var(--space-5);
+ font-weight: 600;
+ font-size: 14px;
+ font-family: var(--font-sans);
+ min-height: 44px;
+ border: none;
+ cursor: pointer;
+ text-decoration: none;
+ transition: transform 150ms var(--ease-out, ease-out), box-shadow 200ms ease-out;
+}
+.btn-primary:hover {
+ transform: translateY(-1px);
+ box-shadow: 0 0 24px oklch(0.65 0.22 270 / 0.35);
+}
+.btn-primary:active {
+ transform: translateY(0);
+}
+
+.btn-ghost {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ gap: var(--space-2);
+ background: transparent;
+ color: var(--muted-foreground);
+ border: 1px solid var(--border);
+ border-radius: var(--space-2);
+ padding: var(--space-2) var(--space-5);
+ font-weight: 500;
+ font-size: 14px;
+ font-family: var(--font-sans);
+ min-height: 44px;
+ cursor: pointer;
+ text-decoration: none;
+ transition: border-color 150ms ease-out, color 150ms ease-out;
+}
+.btn-ghost:hover {
+ border-color: var(--accent);
+ color: var(--accent);
+}
+
+/* ============================================
+ BADGES
+ ============================================ */
+.accent-badge {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--space-1);
+ padding: var(--space-1) var(--space-3);
+ border-radius: 9999px;
+ background: oklch(0.65 0.22 270 / 0.1);
+ color: var(--accent);
+ font-size: 12px;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+}
+.badge-dot {
+ width: 6px;
+ height: 6px;
+ border-radius: 9999px;
+ background: var(--accent);
+}
+
/* ============================================
TERMINAL BLOCK (uteke pattern)
============================================ */
@@ -170,6 +381,132 @@ code, .font-mono {
opacity: 0.4;
}
+/* Terminal internal components */
+.terminal {
+ background: oklch(0.10 0 0);
+ border: 1px solid var(--border);
+ border-radius: var(--space-3);
+ overflow: hidden;
+ font-family: var(--font-mono);
+}
+
+.terminal-header {
+ display: flex;
+ align-items: center;
+ gap: var(--space-2);
+ padding: var(--space-3) var(--space-4);
+ border-bottom: 1px solid oklch(0.27 0.01 270 / 0.5);
+ background: oklch(0.10 0 0);
+}
+
+.terminal-body {
+ padding: var(--space-4) var(--space-5);
+ font-size: 0.8125rem;
+ line-height: 1.625;
+ color: var(--foreground);
+ overflow-x: auto;
+}
+
+.terminal-title {
+ font-size: 12px;
+ font-weight: 500;
+ color: var(--muted-foreground);
+ margin-left: var(--space-2);
+ font-family: var(--font-sans);
+}
+
+.terminal-dot {
+ width: var(--space-2);
+ height: var(--space-2);
+ border-radius: 9999px;
+}
+.terminal-dot-red { background: var(--destructive); }
+.terminal-dot-yellow { background: var(--warning); }
+.terminal-dot-green { background: var(--success); }
+
+/* ============================================
+ SYNTAX HIGHLIGHTING (terminal)
+ ============================================ */
+.syntax-cmd { color: var(--accent-bright); font-weight: 600; }
+.syntax-flag { color: oklch(0.75 0.15 240); }
+.syntax-highlight { color: var(--accent); }
+.syntax-string { color: oklch(0.78 0.16 155); }
+
+/* Cursor blink for terminal demos */
+.typing-cursor {
+ display: inline-block;
+ width: 8px;
+ height: 1.2em;
+ background: var(--accent);
+ vertical-align: text-bottom;
+ animation: blink 1s step-end infinite;
+}
+
+/* Copy button for terminal blocks */
+.copy-btn {
+ position: absolute;
+ top: var(--space-3);
+ right: var(--space-3);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 32px;
+ height: 32px;
+ border-radius: var(--space-1);
+ border: 1px solid var(--border);
+ background: var(--card);
+ color: var(--muted-foreground);
+ cursor: pointer;
+ opacity: 0;
+ transition: opacity 150ms ease, color 150ms ease;
+}
+.terminal:hover .copy-btn,
+.terminal-block:hover .copy-btn { opacity: 1; }
+.copy-btn:hover { color: var(--foreground); }
+
+/* ============================================
+ TIMELINE / FLOW STEPS
+ ============================================ */
+.timeline-step {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ text-align: center;
+ gap: var(--space-3);
+}
+.timeline-number {
+ width: var(--space-10);
+ height: var(--space-10);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 9999px;
+ background: oklch(0.65 0.22 270 / 0.1);
+ color: var(--accent);
+ font-weight: 700;
+ font-size: 18px;
+}
+
+/* ============================================
+ COMPARISON / TABLE SYMBOLS
+ ============================================ */
+.cora-col {
+ background: oklch(0.65 0.22 270 / 0.06);
+}
+.cora-col th,
+.cora-col td {
+ color: var(--accent);
+}
+
+.symbol-check {
+ color: var(--success);
+ font-weight: 700;
+}
+.symbol-cross {
+ color: var(--destructive);
+ font-weight: 700;
+}
+
/* ============================================
FEATURE CARD (uteke pattern)
============================================ */
diff --git a/website/src/lib/components/landing/ComparisonTable.svelte b/website/src/lib/components/landing/ComparisonTable.svelte
new file mode 100644
index 00000000..a0485b02
--- /dev/null
+++ b/website/src/lib/components/landing/ComparisonTable.svelte
@@ -0,0 +1,83 @@
+
+
+ Side-by-side with popular code review tools.
+
+ Why developers choose cora
+
+
+
+
+
+
+
+
+ Feature
+ cora
+ CodeRabbit
+ Copilot
+ SonarQube
+
+
+ BYOK
+ ✓
+ ✗
+ ✗
+ —
+
+
+ Self-hosted
+ ✓
+ ✗
+ ✗
+ ✓
+
+
+ Gitea
+ ✓
+ ✗
+ ✗
+ ✓
+
+
+ CLI
+ ✓
+ ✗
+ ✗
+ ✗
+
+
+ Pre-commit
+ ✓
+ ✗
+ ✗
+ ✗
+
+
+ SARIF
+ ✓
+ ✓
+ ✓
+ ✓
+
+
+ Cost
+ Free + API
+ $12-39/mo
+ $10-39/mo
+ Free / $150+
+
+
+
+ License
+ MIT
+ Apache 2.0
+ Proprietary
+ LGPL
+
{accent}
+{@html description}
++ Everything you need, nothing you don't. +
+ ++ cora catches bugs, security issues, and style violations before they merge. CLI-first. BYOK. Runs in your terminal. +
+ + ++ MIT License · No account · OpenAI · Anthropic · Groq · Ollama +
++ Three steps from code to confidence. +
+ ++ Trusted by developers who ship fast +
++ Run cora against staged changes. Results in seconds, not minutes. +
+ ++ No account required. No subscription. No cloud. +
+ ++ No account. No subscription. No cloud. +
+ +{description}
+{description}
+ {#if terminalCode} + {@render terminalCode()} + {/if} ++ {@render children?.()} +
diff --git a/website/src/lib/components/ui/card/card-footer.svelte b/website/src/lib/components/ui/card/card-footer.svelte new file mode 100644 index 00000000..591c3f71 --- /dev/null +++ b/website/src/lib/components/ui/card/card-footer.svelte @@ -0,0 +1,20 @@ + + +- cora catches bugs, security issues, and style violations before they merge. CLI-first. BYOK. Runs in your terminal. -
- - -- MIT License · No account · OpenAI · Anthropic · Groq · Ollama -
-- Trusted by developers who ship fast -
-- Run cora against staged changes. Results in seconds, not minutes. -
- -- Three steps from code to confidence. -
- -Push your changes as normal. cora only sees your diff.
-cora analyzes your diff with the LLM of your choice.
-Merge clean, production-ready code. Every time.
-- Everything you need, nothing you don't. -
- -Diff, branch, or full scan
-Three review modes: staged diff, branch comparison, or full project scan. LLM-powered analysis catches bugs, security issues, and style violations.
-No subscriptions, no lock-in
-Uses YOUR OpenAI, Anthropic, Groq, Ollama, or Z.AI API key. No data stored on our servers. You control the model, you control the cost.
-Review before you push
-Install once. Every commit gets reviewed automatically. Block bad code from entering your branch before it ships.
-Only scan what changed
-SHA256 content hash cache. First scan indexes your codebase. Subsequent scans only review new or modified files.
-GitHub Code Scanning
-Upload review findings directly to GitHub's Security tab. Track issues across PRs. Works with any CI/CD pipeline.
-Your code stays yours
-Runs entirely on your machine. No cloud, no telemetry, no data leaving your network. Perfect for Gitea and air-gapped environments.
-Same diff, same issues
-Temperature defaults to 0. Identical diffs always produce identical findings — perfect for CI reproducibility.
-Never review the same diff twice
-Reviews are cached by diff hash in ~/.cache/cora/reviews/. Re-reviewing an unchanged diff returns cached results instantly. Use --no-cache to bypass.
Control the review, trust the output
-Override system prompts for review and scan. File path injection and post-parse filtering ensure the LLM only reports issues that exist in your actual diff.
-- Side-by-side with popular code review tools. -
- -| Feature | -cora | -CodeRabbit | -Copilot | -SonarQube | -
|---|---|---|---|---|
| BYOK | -✓ | -✗ | -✗ | -— | -
| Self-hosted | -✓ | -✗ | -✗ | -✓ | -
| Gitea | -✓ | -✗ | -✗ | -✓ | -
| CLI | -✓ | -✗ | -✗ | -✗ | -
| Pre-commit | -✓ | -✗ | -✗ | -✗ | -
| SARIF | -✓ | -✓ | -✓ | -✓ | -
| Cost | -Free + API | -$12-39/mo | -$10-39/mo | -Free / $150+ | -
| License | -MIT | -Apache 2.0 | -Proprietary | -LGPL | -
- No account required. No subscription. No cloud. -
- -Single binary, no dependencies.
-Use your existing OpenAI or Anthropic key.
-Review your staged changes.
-That's it. No account. No subscription.
-- No account. No subscription. No cloud. -
- -Shipped on demand — prioritized by community requests.
Requires sufficient community adoption.