Skip to content

Commit 9ce99f9

Browse files
BunsDevclaude
andauthored
Redesign marketing site with product-aligned landing page (#168)
* Redesign marketing site with product-aligned landing page Replace the placeholder marketing homepage with a full landing page showcasing OK Code features. Adds Tailwind CSS 4, DM Sans font via next/font, and a component-based architecture with Hero (featuring an animated app mockup with chat + diff panels), Feature Grid, How It Works, and Get Started sections. All copy derived from actual product capabilities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * replace Sprint placeholder footer with OK Code footer Minimal footer with OpenKnots attribution and GitHub/Releases/Discord links, replacing the multi-column Sprint placeholder footer. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 332e842 commit 9ce99f9

14 files changed

Lines changed: 1009 additions & 246 deletions

apps/marketing/app/globals.css

Lines changed: 82 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
@import "tailwindcss";
22
@import "tw-animate-css";
33

4-
@custom-variant dark (&:is(.dark *));
4+
@custom-variant dark (&:is(.dark, .dark *));
55

66
/* Add scrollbar-hide utility */
77
@utility scrollbar-hide {
@@ -12,162 +12,62 @@
1212
}
1313
}
1414

15-
/* Custom thin scrollbar styling */
16-
* {
17-
scrollbar-width: thin;
18-
scrollbar-color: var(--muted) var(--secondary);
19-
}
20-
21-
::-webkit-scrollbar {
22-
width: 6px;
23-
}
24-
25-
::-webkit-scrollbar-track {
26-
background: var(--secondary);
27-
}
28-
29-
::-webkit-scrollbar-thumb {
30-
background: var(--muted);
31-
border-radius: 3px;
32-
}
33-
3415
:root {
35-
--background: oklch(1 0 0);
36-
--foreground: oklch(0.145 0 0);
37-
--card: oklch(1 0 0);
38-
--card-foreground: oklch(0.145 0 0);
39-
--popover: oklch(1 0 0);
40-
--popover-foreground: oklch(0.145 0 0);
41-
--primary: oklch(0.205 0 0);
42-
--primary-foreground: oklch(0.985 0 0);
43-
--secondary: oklch(0.97 0 0);
44-
--secondary-foreground: oklch(0.205 0 0);
45-
--muted: oklch(0.97 0 0);
46-
--muted-foreground: oklch(0.556 0 0);
47-
--accent: oklch(0.97 0 0);
48-
--accent-foreground: oklch(0.205 0 0);
49-
--destructive: oklch(0.577 0.245 27.325);
50-
--destructive-foreground: oklch(0.577 0.245 27.325);
51-
--border: oklch(0.922 0 0);
52-
--input: oklch(0.922 0 0);
53-
--ring: oklch(0.708 0 0);
54-
--chart-1: oklch(0.646 0.222 41.116);
55-
--chart-2: oklch(0.6 0.118 184.704);
56-
--chart-3: oklch(0.398 0.07 227.392);
57-
--chart-4: oklch(0.828 0.189 84.429);
58-
--chart-5: oklch(0.769 0.188 70.08);
16+
color-scheme: dark;
5917
--radius: 0.625rem;
60-
--sidebar: oklch(0.985 0 0);
61-
--sidebar-foreground: oklch(0.145 0 0);
62-
--sidebar-primary: oklch(0.205 0 0);
63-
--sidebar-primary-foreground: oklch(0.985 0 0);
64-
--sidebar-accent: oklch(0.97 0 0);
65-
--sidebar-accent-foreground: oklch(0.205 0 0);
66-
--sidebar-border: oklch(0.922 0 0);
67-
--sidebar-ring: oklch(0.708 0 0);
68-
69-
/* Semantic status and UI tokens */
70-
--status-progress: oklch(0.795 0.184 86.047);
71-
--status-success: oklch(0.765 0.177 163.223);
72-
--status-warning: oklch(0.769 0.188 70.08);
73-
--status-error: oklch(0.637 0.237 25.331);
74-
--brand: oklch(0.585 0.233 277.117);
75-
--brand-foreground: oklch(0.985 0 0);
76-
--surface: oklch(0.97 0 0);
77-
--surface-elevated: oklch(0.985 0 0);
78-
--highlight: oklch(0.488 0.243 264.376);
79-
--highlight-foreground: oklch(0.985 0 0);
80-
81-
/* Semantic tokens for favorites/labels */
82-
--favorite-blue: oklch(0.646 0.222 41.116);
83-
--favorite-purple: oklch(0.627 0.265 303.9);
84-
--label-project: oklch(0.828 0.189 84.429);
85-
86-
/* Code syntax highlighting tokens */
87-
--syntax-keyword: oklch(0.646 0.222 41.116);
88-
--syntax-string: oklch(0.6 0.118 184.704);
89-
--syntax-function: oklch(0.828 0.189 84.429);
90-
--syntax-variable: oklch(0.769 0.188 70.08);
91-
92-
/* Added new semantic tokens for landing page sections */
93-
/* Section accent colors */
94-
--accent-ai: oklch(0.623 0.214 259.815);
95-
--accent-workflows: oklch(0.705 0.213 47.604);
96-
--accent-planning: oklch(0.723 0.219 149.579);
9718

98-
/* Code block syntax colors (light mode) */
99-
--code-comment: oklch(0.556 0 0);
100-
--code-keyword: oklch(0.627 0.265 303.9);
101-
--code-string: oklch(0.723 0.219 149.579);
102-
--code-function: oklch(0.769 0.188 70.08);
103-
--code-variable: oklch(0.795 0.184 86.047);
104-
--code-type: oklch(0.6 0.118 184.704);
105-
--code-constant: oklch(0.705 0.213 47.604);
106-
}
107-
108-
.dark {
109-
--background: oklch(0.145 0 0);
110-
--foreground: oklch(0.985 0 0);
111-
--card: oklch(0.145 0 0);
112-
--card-foreground: oklch(0.985 0 0);
113-
--popover: oklch(0.145 0 0);
114-
--popover-foreground: oklch(0.985 0 0);
115-
--primary: oklch(0.985 0 0);
116-
--primary-foreground: oklch(0.205 0 0);
19+
/* Dark-mode-only palette */
20+
--background: color-mix(in srgb, #0a0a1a 95%, white);
21+
--foreground: #f5f5f5;
22+
--card: color-mix(in srgb, #0a0a1a 95%, white);
23+
--card-foreground: #f5f5f5;
24+
--popover: color-mix(in srgb, #0a0a1a 95%, white);
25+
--popover-foreground: #f5f5f5;
26+
--primary: oklch(0.588 0.217 264);
27+
--primary-foreground: #f5f5f5;
11728
--secondary: oklch(0.269 0 0);
118-
--secondary-foreground: oklch(0.985 0 0);
29+
--secondary-foreground: #f5f5f5;
11930
--muted: oklch(0.269 0 0);
120-
--muted-foreground: oklch(0.708 0 0);
31+
--muted-foreground: color-mix(in srgb, #a3a3a3 90%, white);
12132
--accent: oklch(0.269 0 0);
122-
--accent-foreground: oklch(0.985 0 0);
33+
--accent-foreground: #f5f5f5;
12334
--destructive: oklch(0.396 0.141 25.723);
12435
--destructive-foreground: oklch(0.637 0.237 25.331);
125-
--border: oklch(0.269 0 0);
126-
--input: oklch(0.269 0 0);
127-
--ring: oklch(0.439 0 0);
36+
--border: oklch(1 0 0 / 0.06);
37+
--input: oklch(1 0 0 / 0.06);
38+
--ring: oklch(0.588 0.217 264 / 0.4);
39+
40+
/* Chart colors */
12841
--chart-1: oklch(0.488 0.243 264.376);
12942
--chart-2: oklch(0.696 0.17 162.48);
13043
--chart-3: oklch(0.769 0.188 70.08);
13144
--chart-4: oklch(0.627 0.265 303.9);
13245
--chart-5: oklch(0.645 0.246 16.439);
46+
47+
/* Sidebar */
13348
--sidebar: oklch(0.205 0 0);
134-
--sidebar-foreground: oklch(0.985 0 0);
135-
--sidebar-primary: oklch(0.488 0.243 264.376);
136-
--sidebar-primary-foreground: oklch(0.985 0 0);
49+
--sidebar-foreground: #f5f5f5;
50+
--sidebar-primary: oklch(0.588 0.217 264);
51+
--sidebar-primary-foreground: #f5f5f5;
13752
--sidebar-accent: oklch(0.269 0 0);
138-
--sidebar-accent-foreground: oklch(0.985 0 0);
139-
--sidebar-border: oklch(0.269 0 0);
140-
--sidebar-ring: oklch(0.439 0 0);
53+
--sidebar-accent-foreground: #f5f5f5;
54+
--sidebar-border: oklch(1 0 0 / 0.06);
55+
--sidebar-ring: oklch(0.588 0.217 264 / 0.4);
14156

142-
/* Dark mode semantic tokens */
143-
--status-progress: oklch(0.795 0.184 86.047);
144-
--status-success: oklch(0.765 0.177 163.223);
145-
--status-warning: oklch(0.769 0.188 70.08);
146-
--status-error: oklch(0.637 0.237 25.331);
57+
/* Semantic tokens */
14758
--brand: oklch(0.585 0.233 277.117);
148-
--brand-foreground: oklch(0.985 0 0);
59+
--brand-foreground: #f5f5f5;
14960
--surface: oklch(0.205 0 0);
15061
--surface-elevated: oklch(0.269 0 0);
15162
--highlight: oklch(0.585 0.233 277.117);
152-
--highlight-foreground: oklch(0.985 0 0);
153-
154-
/* Dark mode favorites/labels */
155-
--favorite-blue: oklch(0.488 0.243 264.376);
156-
--favorite-purple: oklch(0.627 0.265 303.9);
157-
--label-project: oklch(0.627 0.265 303.9);
63+
--highlight-foreground: #f5f5f5;
15864

159-
/* Code syntax highlighting tokens - dark mode */
160-
--syntax-keyword: oklch(0.488 0.243 264.376);
161-
--syntax-string: oklch(0.696 0.17 162.48);
162-
--syntax-function: oklch(0.627 0.265 303.9);
163-
--syntax-variable: oklch(0.769 0.188 70.08);
164-
165-
/* Dark mode landing page tokens */
65+
/* Landing page section accents */
16666
--accent-ai: oklch(0.623 0.214 259.815);
16767
--accent-workflows: oklch(0.705 0.213 47.604);
16868
--accent-planning: oklch(0.723 0.219 149.579);
16969

170-
/* Code block syntax colors (dark mode) */
70+
/* Code syntax */
17171
--code-comment: oklch(0.439 0 0);
17272
--code-keyword: oklch(0.627 0.265 303.9);
17373
--code-string: oklch(0.723 0.219 149.579);
@@ -178,8 +78,10 @@
17878
}
17979

18080
@theme inline {
181-
--font-sans: "Geist", "Geist Fallback";
182-
--font-mono: "Geist Mono", "Geist Mono Fallback";
81+
--font-sans: var(--font-dm-sans), "DM Sans", -apple-system, BlinkMacSystemFont,
82+
"Segoe UI", system-ui, sans-serif;
83+
--font-mono: "SF Mono", "SFMono-Regular", Consolas, "Liberation Mono", Menlo,
84+
monospace;
18385
--color-background: var(--background);
18486
--color-foreground: var(--foreground);
18587
--color-card: var(--card);
@@ -216,29 +118,12 @@
216118
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
217119
--color-sidebar-border: var(--sidebar-border);
218120
--color-sidebar-ring: var(--sidebar-ring);
219-
220-
/* Register semantic tokens in theme */
221-
--color-status-progress: var(--status-progress);
222-
--color-status-success: var(--status-success);
223-
--color-status-warning: var(--status-warning);
224-
--color-status-error: var(--status-error);
225121
--color-brand: var(--brand);
226122
--color-brand-foreground: var(--brand-foreground);
227123
--color-surface: var(--surface);
228124
--color-surface-elevated: var(--surface-elevated);
229125
--color-highlight: var(--highlight);
230126
--color-highlight-foreground: var(--highlight-foreground);
231-
232-
/* Register favorites/labels tokens */
233-
--color-favorite-blue: var(--favorite-blue);
234-
--color-favorite-purple: var(--favorite-purple);
235-
--color-label-project: var(--label-project);
236-
--color-syntax-keyword: var(--syntax-keyword);
237-
--color-syntax-string: var(--syntax-string);
238-
--color-syntax-function: var(--syntax-function);
239-
--color-syntax-variable: var(--syntax-variable);
240-
241-
/* Register new landing page semantic tokens */
242127
--color-accent-ai: var(--accent-ai);
243128
--color-accent-workflows: var(--accent-workflows);
244129
--color-accent-planning: var(--accent-planning);
@@ -258,9 +143,53 @@
258143
body {
259144
@apply bg-background text-foreground;
260145
}
261-
/* Add text selection styling */
262146
::selection {
263-
background-color: var(--brand);
147+
background-color: var(--primary);
264148
color: white;
265149
}
266150
}
151+
152+
/* Fractal noise texture overlay */
153+
body::after {
154+
content: "";
155+
position: fixed;
156+
inset: 0;
157+
z-index: 9999;
158+
pointer-events: none;
159+
opacity: 0.035;
160+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
161+
}
162+
163+
/* Heading scale */
164+
h1 {
165+
font-size: clamp(2.25rem, 5vw, 3.75rem);
166+
line-height: 1.1;
167+
font-weight: 600;
168+
letter-spacing: -0.025em;
169+
}
170+
171+
h2 {
172+
font-size: clamp(1.5rem, 3.5vw, 2.25rem);
173+
line-height: 1.2;
174+
font-weight: 600;
175+
letter-spacing: -0.02em;
176+
}
177+
178+
/* Custom thin scrollbar styling */
179+
* {
180+
scrollbar-width: thin;
181+
scrollbar-color: var(--muted) transparent;
182+
}
183+
184+
::-webkit-scrollbar {
185+
width: 6px;
186+
}
187+
188+
::-webkit-scrollbar-track {
189+
background: transparent;
190+
}
191+
192+
::-webkit-scrollbar-thumb {
193+
background: var(--muted);
194+
border-radius: 3px;
195+
}

apps/marketing/app/layout.tsx

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,41 @@
11
import type React from "react";
22
import type { Metadata } from "next";
3-
import { Geist, Geist_Mono } from "next/font/google";
3+
import { DM_Sans } from "next/font/google";
44
import { Analytics } from "@vercel/analytics/next";
55
import "./globals.css";
66

7-
const _geist = Geist({ subsets: ["latin"] });
8-
const _geistMono = Geist_Mono({ subsets: ["latin"] });
7+
const dmSans = DM_Sans({
8+
subsets: ["latin"],
9+
variable: "--font-dm-sans",
10+
});
911

1012
export const metadata: Metadata = {
11-
title: "Sprint - Purpose-built tool for planning and building products",
13+
title: "OK Code — A Minimal Web GUI for Coding Agents",
1214
description:
13-
"Meet the system for modern software development. Streamline issues, projects, and product roadmaps with Sprint.",
14-
generator: "v0.app",
15+
"Chat with Codex and Claude in a modern web UI. Git worktree isolation, diff review, integrated terminal, and more. Run anywhere with npx okcodes.",
1516
keywords: [
16-
"project management",
17-
"product development",
18-
"issue tracking",
19-
"roadmap planning",
20-
"team collaboration",
17+
"coding agents",
18+
"AI coding",
19+
"web GUI",
20+
"git worktree",
21+
"diff review",
22+
"Claude",
23+
"Codex",
24+
"terminal",
2125
],
22-
authors: [{ name: "Sprint" }],
26+
authors: [{ name: "OpenKnots" }],
2327
openGraph: {
24-
title: "Sprint - Purpose-built tool for planning and building products",
28+
title: "OK Code — A Minimal Web GUI for Coding Agents",
2529
description:
26-
"Meet the system for modern software development. Streamline issues, projects, and product roadmaps.",
30+
"Chat with Codex and Claude in a modern web UI. Git worktree isolation, diff review, integrated terminal, and more.",
2731
type: "website",
2832
locale: "en_US",
2933
},
3034
twitter: {
3135
card: "summary_large_image",
32-
title: "Sprint - Purpose-built tool for planning and building products",
36+
title: "OK Code — A Minimal Web GUI for Coding Agents",
3337
description:
34-
"Meet the system for modern software development. Streamline issues, projects, and product roadmaps.",
38+
"Chat with Codex and Claude in a modern web UI. Git worktree isolation, diff review, integrated terminal, and more.",
3539
},
3640
icons: {
3741
icon: [
@@ -58,8 +62,8 @@ export default function RootLayout({
5862
children: React.ReactNode;
5963
}>) {
6064
return (
61-
<html lang="en">
62-
<body className={`font-sans antialiased`}>
65+
<html lang="en" className="dark">
66+
<body className={`${dmSans.variable} font-sans antialiased`}>
6367
{children}
6468
<Analytics />
6569
</body>

apps/marketing/app/page.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
1-
import { Hero3DStage } from "@/components/hero-3d-stage";
1+
import { Nav } from "@/components/Nav";
2+
import { Hero } from "@/components/Hero";
3+
import { FeatureGrid } from "@/components/FeatureGrid";
4+
import { HowItWorks } from "@/components/HowItWorks";
5+
import { GetStarted } from "@/components/GetStarted";
6+
import { Footer } from "@/components/Footer";
27

38
export default function Home() {
49
return (
5-
<main>
6-
<Hero3DStage />
10+
<main className="min-h-screen">
11+
<Nav />
12+
<Hero />
13+
<FeatureGrid />
14+
<HowItWorks />
15+
<GetStarted />
16+
<Footer />
717
</main>
818
);
919
}

0 commit comments

Comments
 (0)