From a782e3dac2c60429c2f06ccb1b20edaf5797ca0f Mon Sep 17 00:00:00 2001 From: Dax Date: Wed, 1 Oct 2025 19:38:15 -0400 Subject: Zen lander (#2907) Co-authored-by: David Hill Co-authored-by: GitHub Action Co-authored-by: Adam <2363879+adamdotdevin@users.noreply.github.com> Co-authored-by: Jay V --- packages/app/package.json | 2 +- packages/console/app/package.json | 1 + packages/console/app/public/favicon-zen.svg | 23 + packages/console/app/public/favicon.svg | 8 +- packages/console/app/public/social-share-zen.png | Bin 0 -> 21918 bytes packages/console/app/public/social-share.png | Bin 17520 -> 8923 bytes .../console/app/src/asset/lander/avatar-adam.png | Bin 0 -> 8062 bytes .../console/app/src/asset/lander/avatar-david.png | Bin 0 -> 7019 bytes .../console/app/src/asset/lander/avatar-dax.png | Bin 0 -> 9390 bytes .../console/app/src/asset/lander/avatar-frank.png | Bin 0 -> 7535 bytes .../console/app/src/asset/lander/avatar-jay.png | Bin 0 -> 6337 bytes packages/console/app/src/asset/lander/check.svg | 5 +- packages/console/app/src/asset/lander/copy.svg | 5 +- packages/console/app/src/asset/lander/dock.png | Bin 0 -> 7414 bytes .../src/asset/lander/opencode-comparison-min.mp4 | Bin 0 -> 16908501 bytes .../asset/lander/opencode-comparison-poster.png | Bin 0 -> 53916 bytes .../console/app/src/asset/lander/opencode-min.mp4 | Bin 0 -> 24455677 bytes .../app/src/asset/lander/opencode-poster.png | Bin 0 -> 53916 bytes .../app/src/asset/lander/screenshot-github.png | Bin 924094 -> 232073 bytes .../app/src/asset/lander/screenshot-splash.png | Bin 467281 -> 133399 bytes .../app/src/asset/lander/screenshot-vscode.png | Bin 1022418 -> 507258 bytes .../console/app/src/asset/lander/screenshot.png | Bin 606051 -> 139488 bytes .../console/app/src/asset/logo-ornate-dark.svg | 35 +- .../console/app/src/asset/logo-ornate-light.svg | 34 +- packages/console/app/src/asset/logo.svg | 28 +- packages/console/app/src/asset/zen-ornate-dark.svg | 8 + .../console/app/src/asset/zen-ornate-light.svg | 8 + .../console/app/src/component/email-signup.tsx | 49 + packages/console/app/src/component/faq.tsx | 33 + packages/console/app/src/component/footer.tsx | 34 + packages/console/app/src/component/header.tsx | 127 ++ packages/console/app/src/component/icon.tsx | 33 +- packages/console/app/src/component/legal.tsx | 9 + packages/console/app/src/lib/github.ts | 28 + packages/console/app/src/routes/index.css | 1139 +++++++++++++----- packages/console/app/src/routes/index.tsx | 1257 +++++++++++++++++--- packages/console/app/src/routes/temp.tsx | 183 +++ packages/console/app/src/routes/zen/index.css | 781 ++++++++++++ packages/console/app/src/routes/zen/index.tsx | 339 ++++++ packages/console/app/src/style/base.css | 12 + 40 files changed, 3663 insertions(+), 518 deletions(-) create mode 100644 packages/console/app/public/favicon-zen.svg create mode 100644 packages/console/app/public/social-share-zen.png create mode 100644 packages/console/app/src/asset/lander/avatar-adam.png create mode 100644 packages/console/app/src/asset/lander/avatar-david.png create mode 100644 packages/console/app/src/asset/lander/avatar-dax.png create mode 100644 packages/console/app/src/asset/lander/avatar-frank.png create mode 100644 packages/console/app/src/asset/lander/avatar-jay.png create mode 100644 packages/console/app/src/asset/lander/dock.png create mode 100644 packages/console/app/src/asset/lander/opencode-comparison-min.mp4 create mode 100644 packages/console/app/src/asset/lander/opencode-comparison-poster.png create mode 100644 packages/console/app/src/asset/lander/opencode-min.mp4 create mode 100644 packages/console/app/src/asset/lander/opencode-poster.png create mode 100644 packages/console/app/src/asset/zen-ornate-dark.svg create mode 100644 packages/console/app/src/asset/zen-ornate-light.svg create mode 100644 packages/console/app/src/component/email-signup.tsx create mode 100644 packages/console/app/src/component/faq.tsx create mode 100644 packages/console/app/src/component/footer.tsx create mode 100644 packages/console/app/src/component/header.tsx create mode 100644 packages/console/app/src/component/legal.tsx create mode 100644 packages/console/app/src/lib/github.ts create mode 100644 packages/console/app/src/routes/temp.tsx create mode 100644 packages/console/app/src/routes/zen/index.css create mode 100644 packages/console/app/src/routes/zen/index.tsx (limited to 'packages') diff --git a/packages/app/package.json b/packages/app/package.json index 8a0fc8075..cea89b570 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -21,7 +21,7 @@ "vite-plugin-solid": "^2.11.6" }, "dependencies": { - "@kobalte/core": "0.13.11", + "@kobalte/core": "catalog:", "@opencode-ai/sdk": "workspace:*", "@shikijs/transformers": "3.9.2", "@solid-primitives/event-bus": "1.1.2", diff --git a/packages/console/app/package.json b/packages/console/app/package.json index 18a2f5e23..6146a4f4a 100644 --- a/packages/console/app/package.json +++ b/packages/console/app/package.json @@ -11,6 +11,7 @@ }, "dependencies": { "@ibm/plex": "6.4.1", + "@kobalte/core": "catalog:", "@jsx-email/render": "1.1.1", "@openauthjs/openauth": "0.0.0-20250322224806", "@opencode/console-core": "workspace:*", diff --git a/packages/console/app/public/favicon-zen.svg b/packages/console/app/public/favicon-zen.svg new file mode 100644 index 000000000..84aeff32f --- /dev/null +++ b/packages/console/app/public/favicon-zen.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/public/favicon.svg b/packages/console/app/public/favicon.svg index 3c81bbdb4..d36e41f94 100644 --- a/packages/console/app/public/favicon.svg +++ b/packages/console/app/public/favicon.svg @@ -1,5 +1,5 @@ - - - - + + + + diff --git a/packages/console/app/public/social-share-zen.png b/packages/console/app/public/social-share-zen.png new file mode 100644 index 000000000..33e941441 Binary files /dev/null and b/packages/console/app/public/social-share-zen.png differ diff --git a/packages/console/app/public/social-share.png b/packages/console/app/public/social-share.png index 97f67994d..92224f54c 100644 Binary files a/packages/console/app/public/social-share.png and b/packages/console/app/public/social-share.png differ diff --git a/packages/console/app/src/asset/lander/avatar-adam.png b/packages/console/app/src/asset/lander/avatar-adam.png new file mode 100644 index 000000000..d94a0a9a4 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-adam.png differ diff --git a/packages/console/app/src/asset/lander/avatar-david.png b/packages/console/app/src/asset/lander/avatar-david.png new file mode 100644 index 000000000..2e65272e3 Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-david.png differ diff --git a/packages/console/app/src/asset/lander/avatar-dax.png b/packages/console/app/src/asset/lander/avatar-dax.png new file mode 100644 index 000000000..0ee8feace Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-dax.png differ diff --git a/packages/console/app/src/asset/lander/avatar-frank.png b/packages/console/app/src/asset/lander/avatar-frank.png new file mode 100644 index 000000000..5e8f7715f Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-frank.png differ diff --git a/packages/console/app/src/asset/lander/avatar-jay.png b/packages/console/app/src/asset/lander/avatar-jay.png new file mode 100644 index 000000000..2f74ca8dc Binary files /dev/null and b/packages/console/app/src/asset/lander/avatar-jay.png differ diff --git a/packages/console/app/src/asset/lander/check.svg b/packages/console/app/src/asset/lander/check.svg index 22de6f2a8..0ac7759ea 100644 --- a/packages/console/app/src/asset/lander/check.svg +++ b/packages/console/app/src/asset/lander/check.svg @@ -1,2 +1,3 @@ - - + + + diff --git a/packages/console/app/src/asset/lander/copy.svg b/packages/console/app/src/asset/lander/copy.svg index f1baac30a..e2263279e 100644 --- a/packages/console/app/src/asset/lander/copy.svg +++ b/packages/console/app/src/asset/lander/copy.svg @@ -1,2 +1,3 @@ - - + + + diff --git a/packages/console/app/src/asset/lander/dock.png b/packages/console/app/src/asset/lander/dock.png new file mode 100644 index 000000000..c9087d461 Binary files /dev/null and b/packages/console/app/src/asset/lander/dock.png differ diff --git a/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 b/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 new file mode 100644 index 000000000..3cfa15b36 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-comparison-min.mp4 differ diff --git a/packages/console/app/src/asset/lander/opencode-comparison-poster.png b/packages/console/app/src/asset/lander/opencode-comparison-poster.png new file mode 100644 index 000000000..4542a1c86 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-comparison-poster.png differ diff --git a/packages/console/app/src/asset/lander/opencode-min.mp4 b/packages/console/app/src/asset/lander/opencode-min.mp4 new file mode 100644 index 000000000..47468bedf Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-min.mp4 differ diff --git a/packages/console/app/src/asset/lander/opencode-poster.png b/packages/console/app/src/asset/lander/opencode-poster.png new file mode 100644 index 000000000..4542a1c86 Binary files /dev/null and b/packages/console/app/src/asset/lander/opencode-poster.png differ diff --git a/packages/console/app/src/asset/lander/screenshot-github.png b/packages/console/app/src/asset/lander/screenshot-github.png index fda74e641..a421598ee 100644 Binary files a/packages/console/app/src/asset/lander/screenshot-github.png and b/packages/console/app/src/asset/lander/screenshot-github.png differ diff --git a/packages/console/app/src/asset/lander/screenshot-splash.png b/packages/console/app/src/asset/lander/screenshot-splash.png index e900673ef..98e9b477c 100644 Binary files a/packages/console/app/src/asset/lander/screenshot-splash.png and b/packages/console/app/src/asset/lander/screenshot-splash.png differ diff --git a/packages/console/app/src/asset/lander/screenshot-vscode.png b/packages/console/app/src/asset/lander/screenshot-vscode.png index b8966a6b8..4297948e5 100644 Binary files a/packages/console/app/src/asset/lander/screenshot-vscode.png and b/packages/console/app/src/asset/lander/screenshot-vscode.png differ diff --git a/packages/console/app/src/asset/lander/screenshot.png b/packages/console/app/src/asset/lander/screenshot.png index feb617585..26975bc89 100644 Binary files a/packages/console/app/src/asset/lander/screenshot.png and b/packages/console/app/src/asset/lander/screenshot.png differ diff --git a/packages/console/app/src/asset/logo-ornate-dark.svg b/packages/console/app/src/asset/logo-ornate-dark.svg index 2efda934d..a15827324 100644 --- a/packages/console/app/src/asset/logo-ornate-dark.svg +++ b/packages/console/app/src/asset/logo-ornate-dark.svg @@ -1,19 +1,18 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - diff --git a/packages/console/app/src/asset/logo-ornate-light.svg b/packages/console/app/src/asset/logo-ornate-light.svg index 789223bc4..2a856dcce 100644 --- a/packages/console/app/src/asset/logo-ornate-light.svg +++ b/packages/console/app/src/asset/logo-ornate-light.svg @@ -1,18 +1,18 @@ - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/logo.svg b/packages/console/app/src/asset/logo.svg index cbfcccf51..2a856dcce 100644 --- a/packages/console/app/src/asset/logo.svg +++ b/packages/console/app/src/asset/logo.svg @@ -1,12 +1,18 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + + diff --git a/packages/console/app/src/asset/zen-ornate-dark.svg b/packages/console/app/src/asset/zen-ornate-dark.svg new file mode 100644 index 000000000..cdc4485fc --- /dev/null +++ b/packages/console/app/src/asset/zen-ornate-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/console/app/src/asset/zen-ornate-light.svg b/packages/console/app/src/asset/zen-ornate-light.svg new file mode 100644 index 000000000..2a9ed1342 --- /dev/null +++ b/packages/console/app/src/asset/zen-ornate-light.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packages/console/app/src/component/email-signup.tsx b/packages/console/app/src/component/email-signup.tsx new file mode 100644 index 000000000..fec516a5f --- /dev/null +++ b/packages/console/app/src/component/email-signup.tsx @@ -0,0 +1,49 @@ +import { action, useSubmission } from "@solidjs/router" +import dock from "../asset/lander/dock.png" +import { Resource } from "sst" +import { Show } from "solid-js" + +const emailSignup = action(async (formData: FormData) => { + "use server" + const emailAddress = formData.get("email")! + const listId = "8b9bb82c-9d5f-11f0-975f-0df6fd1e4945" + const response = await fetch(`https://api.emailoctopus.com/lists/${listId}/contacts`, { + method: "PUT", + headers: { + Authorization: `Bearer ${Resource.EMAILOCTOPUS_API_KEY.value}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + email_address: emailAddress, + }), + }) + console.log(response) + return true +}) + +export function EmailSignup() { + const submission = useSubmission(emailSignup) + return ( +
+
+ +
+
+

OpenCode will be available on desktop soon

+

Join the waitlist for early access.

+
+
+ + +
+ +
Almost done, check your inbox and confirm your email address
+
+ +
{submission.error}
+
+ + ) +} diff --git a/packages/console/app/src/component/faq.tsx b/packages/console/app/src/component/faq.tsx new file mode 100644 index 000000000..2b28fc0fe --- /dev/null +++ b/packages/console/app/src/component/faq.tsx @@ -0,0 +1,33 @@ +import { Collapsible } from "@kobalte/core/collapsible" +import { ParentProps } from "solid-js" + +export function Faq(props: ParentProps & { question: string }) { + return ( + + + + + + + + +
{props.question}
+
+ {props.children} +
+ ) +} diff --git a/packages/console/app/src/component/footer.tsx b/packages/console/app/src/component/footer.tsx new file mode 100644 index 000000000..f4ff846db --- /dev/null +++ b/packages/console/app/src/component/footer.tsx @@ -0,0 +1,34 @@ +import { A, createAsync } from "@solidjs/router" +import { createMemo } from "solid-js" +import { github } from "~/lib/github" + +export function Footer() { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()!.stars!) + : "25K", + ) + + return ( + + ) +} diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx new file mode 100644 index 000000000..c5447d1c1 --- /dev/null +++ b/packages/console/app/src/component/header.tsx @@ -0,0 +1,127 @@ +import logoLight from "../asset/logo-ornate-light.svg" +import logoDark from "../asset/logo-ornate-dark.svg" +import { A, createAsync } from "@solidjs/router" +import { createMemo, Match, Show, Switch } from "solid-js" +import { createStore } from "solid-js/store" +import { github } from "~/lib/github" + +export function Header(props: { zen?: boolean }) { + const githubData = createAsync(() => github()) + const starCount = createMemo(() => + githubData()?.stars + ? new Intl.NumberFormat("en-US", { + notation: "compact", + compactDisplay: "short", + }).format(githubData()?.stars!) + : "25K", + ) + + const [store, setStore] = createStore({ + mobileMenuOpen: false, + }) + + return ( +
+ + opencode logo light + opencode logo dark + + + +
+ ) +} diff --git a/packages/console/app/src/component/icon.tsx b/packages/console/app/src/component/icon.tsx index a82572e62..fa28316e8 100644 --- a/packages/console/app/src/component/icon.tsx +++ b/packages/console/app/src/component/icon.tsx @@ -34,38 +34,21 @@ export function IconLogo(props: JSX.SvgSVGAttributes) { export function IconCopy(props: JSX.SvgSVGAttributes) { return ( - - + + d="M8.75 8.75V2.75H21.25V15.25H15.25M15.25 8.75H2.75V21.25H15.25V8.75Z" + stroke="#8E8B8B" + stroke-width="1.5" + stroke-linecap="square" + /> ) } export function IconCheck(props: JSX.SvgSVGAttributes) { return ( - - + + ) } diff --git a/packages/console/app/src/component/legal.tsx b/packages/console/app/src/component/legal.tsx new file mode 100644 index 000000000..d692e4622 --- /dev/null +++ b/packages/console/app/src/component/legal.tsx @@ -0,0 +1,9 @@ +export function Legal() { + return ( +
+ + ©{new Date().getFullYear()} Anomaly + +
+ ) +} diff --git a/packages/console/app/src/lib/github.ts b/packages/console/app/src/lib/github.ts new file mode 100644 index 000000000..49b926463 --- /dev/null +++ b/packages/console/app/src/lib/github.ts @@ -0,0 +1,28 @@ +import { query } from "@solidjs/router" + +export const github = query(async () => { + "use server" + try { + const [meta, releases, contributors] = await Promise.all([ + fetch("https://api.github.com/repos/sst/opencode").then((res) => res.json()), + fetch("https://api.github.com/repos/sst/opencode/releases").then((res) => res.json()), + fetch("https://api.github.com/repos/sst/opencode/contributors?per_page=1"), + ]) + const [release] = releases + const contributorCount = Number.parseInt( + contributors.headers + .get("Link")! + .match(/&page=(\d+)>; rel="last"/)! + .at(1)!, + ) + return { + stars: meta.stargazers_count, + release: { + name: release.name, + url: release.html_url, + }, + contributors: contributorCount, + } + } catch {} + return undefined +}, "github") diff --git a/packages/console/app/src/routes/index.css b/packages/console/app/src/routes/index.css index fe95bb7ea..9ded25460 100644 --- a/packages/console/app/src/routes/index.css +++ b/packages/console/app/src/routes/index.css @@ -1,32 +1,67 @@ -[data-page="home"] { - --color-text: hsl(224, 10%, 10%); - --color-text-secondary: hsl(224, 7%, 46%); - --color-text-dimmed: hsl(224, 6%, 63%); - --color-text-inverted: hsl(0, 0%, 100%); +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); - --color-border: hsl(224, 6%, 77%); + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } } -[data-page="home"] { - @media (prefers-color-scheme: dark) { - --color-text: hsl(0, 0%, 100%); - --color-text-secondary: hsl(224, 6%, 66%); - --color-text-dimmed: hsl(224, 7%, 46%); - --color-text-inverted: hsl(224, 10%, 10%); +[data-page="opencode"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-weak-hover: hsl(0, 8%, 94%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 60%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); +} - --color-border: hsl(224, 6%, 36%); +[data-page="opencode"] { + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-weak-hover: hsl(0, 6%, 15%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); } } -[data-page="home"] { - --padding: 3rem; - --vertical-padding: 1.5rem; +[data-page="opencode"] { + background: var(--color-background); + --padding: 5rem; + --vertical-padding: 4rem; --heading-font-size: 1.375rem; + border-top: 1px solid var(--color-border-weak); - @media (max-width: 30rem) { - --padding: 1rem; - --vertical-padding: 0.75rem; - --heading-font-size: 1rem; + @media (max-width: 60rem) { + --padding: 1.5rem; + --vertical-padding: 3rem; } display: flex; @@ -34,32 +69,215 @@ flex-direction: column; font-family: var(--font-mono); color: var(--color-text); - padding: calc(var(--padding) + 1rem); + padding-bottom: 5rem; a { - color: var(--color-text); + color: var(--color-text-strong); text-decoration: underline; - text-underline-offset: var(--space-0-75); + text-underline-offset: var(--space-1); text-decoration-thickness: 1px; } - [data-component="content"] { + p { + line-height: 200%; + } + + @media (max-width: 60rem) { + font-size: 15px; + } + + [data-component="growth-stats"] { + margin-top: 48px; + margin-left: 40px; + display: flex; + gap: 64px !important; + + @media (max-width: 60rem) { + gap: 56px !important; + } + + @media (max-width: 50rem) { + gap: 48px !important; + } + + @media (max-width: 40rem) { + display: none !important; + } + + + [data-component="growth-stat"] { + display: flex; + flex-direction: column; + gap: 24px; + text-align: left; + width: 100%; + + span { + display: flex; + align-items: center; + justify-content: left; + width: 100%; + gap: 10px; + font-size: 14px; + + strong { + color: var(--color-text-strong); + font-weight: 500; + } + + figure { + font-size: 14px; + color: var(--color-text-weak); + padding: 0; + margin: 0; + + @media (max-width: 70rem) { + display: none; + } + } + + } + + + [data-component="stat-illustration"] { + width: 100%; + height: 100%; + display: block; + + svg { + margin: 0; + width: auto; + height: auto; + display: block; + } + } + } + } + + + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + transition: background-color 5000000s ease-in-out 0s; + } + + [data-component="container"] { max-width: 67.5rem; margin: 0 auto; - border: 1px solid var(--color-border); + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { } [data-component="top"] { - padding: calc(var(--padding) * 1.5) var(--padding) var(--padding); - position: relative; + padding: 24px var(--padding); + height: 80px; + position: sticky; + top: 0; display: flex; - flex-direction: column; + justify-content: space-between; align-items: center; - gap: calc(var(--vertical-padding) / 2); + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + + z-index: 10; img { - height: auto; - width: clamp(200px, 85vw, 552px); + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + gap: 48px; + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: var(--space-1); + text-decoration-thickness: 1px; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } } [data-slot="logo dark"] { @@ -74,374 +292,690 @@ display: block; } } + } - [data-slot="title"] { - line-height: 1.25; - font-weight: 500; - text-align: center; - font-size: var(--heading-font-size); - color: var(--color-text-secondary); - text-transform: uppercase; - } + [data-component="hero"] { + display: flex; + flex-direction: column; + max-width: 100%; + padding: calc(var(--vertical-padding)*2) var(--padding); - [data-slot="login"] { - position: absolute; - top: 0; - right: 0; - border-width: 0 0 1px 1px; - border-style: solid; - border-color: var(--color-border); - background-color: var(--color-bg); + @media (max-width: 30rem) { + padding: var(--vertical-padding) var(--padding) + } - @media (max-width: 30rem) { + @media (prefers-color-scheme: dark) { + [data-slot="zen logo light"] { display: none; } - - a { + [data-slot="zen logo dark"] { display: block; - padding: 0.5rem 1rem calc(0.5rem + 4px); } } } - [data-component="cta"] { - border-top: 1px solid var(--color-border); - display: flex; + [data-slot="installation"] { + width: 100%; + max-width: 100%; + overflow: hidden; - & > div + div { - border-left: 1px solid var(--color-border); + @media (max-width: 550px) { + width: calc(100vw - 48px); } - [data-slot="left"] { - flex: 0 0 auto; - text-align: center; - line-height: 1.4; - padding: var(--vertical-padding) 2rem; - text-transform: uppercase; - font-size: 1.125rem; - - @media (max-width: 30rem) { - font-size: 1rem; - padding-bottom: calc(var(--vertical-padding) + 4px); - } + } - @media (max-width: 30rem) { - padding-left: 0.5rem; - padding-right: 0.5rem; + [data-component="tabs"] { + [data-slot="tablist"] { + display: flex; + gap: 40px; + align-items: center; + border: 1px solid var(--color-border-weak); + border-bottom: none; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + background: var(--color-background-weak); + padding: 0 20px; + + @media (max-width: 60rem) { + gap: 20px; + overflow-x: auto; + width: 100%; } } - [data-slot="center"] { - display: none; - - @media (max-width: 30rem) { - display: block; - flex: 1; - text-align: center; - padding: var(--vertical-padding) 0.5rem; - border-top: 1px solid var(--color-border); - border-left: none; - } + [data-slot="tab"] { + appearance: none; + background: transparent; + border: 0; + padding: 16px 0; + margin: 0; + cursor: pointer; + color: var(--color-text-weak); + line-height: 1; + border-bottom: 2px solid transparent; } - [data-slot="right"] { - flex: 1; - padding: var(--vertical-padding) 1rem; + [data-slot="tab"][aria-selected="true"] { + color: var(--color-text-strong); + border-bottom-color: var(--color-background-strong); } - @media (max-width: 50rem) { - flex-direction: column; + [data-slot="tab"]:focus-visible { + } - [data-slot="right"] { - border-left: none; - border-top: 1px solid var(--color-border); - } + [data-slot="panels"] { + background: var(--color-background-weak); + border: 1px solid var(--color-border-weak); + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + padding: 16px; } - [data-slot="command"] { - all: unset; - display: flex; - align-items: center; - justify-content: center; - cursor: pointer; - color: var(--color-text-secondary); - font-size: 1.125rem; + [data-slot="panel"] { + display: block; + margin: 0; + overflow: auto; + white-space: pre-wrap; + transition: opacity 0.18s ease; + font-size: 16px; font-family: var(--font-mono); - gap: var(--space-2); width: 100%; - & > span { - @media (max-width: 24rem) { - font-size: 0.875rem; - } - @media (max-width: 56rem) { - [data-slot="protocol"] { - display: none; + button { + max-width: 100%; + } + + [data-slot="command"] { + all: unset; + display: flex; + max-width: 100%; + cursor: pointer; + align-items: center; + color: var(--color-text); + gap: var(--space-1); + color: var(--color-text); + padding: 8px 16px 8px 8px; + border-radius: 4px; + + [data-slot="command-script"] { + display: inline-block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + vertical-align: middle; + + @media (prefers-color-scheme: dark) { + color: var(--color-text-weak); } - } - @media (max-width: 38rem) { - text-align: center; - span:first-child { - display: block; + + @media (max-width: 35rem) { + width: calc(100% - 40px) !important; } + + } + + [data-slot="highlight"] { + font-weight: 500; + color: var(--color-text-strong); + } + } + + [data-slot="command"]:hover { + background: var(--color-background-weak-hover); + + @media (prefers-color-scheme: dark) { + color: var(--color-text-weak); + background: var(--color-background-weak-hover); } } } + } - [data-slot="highlight"] { - color: var(--color-text); + [data-slot="hero-copy"] { + [data-slot="releases"] { + background: none; + color: var(--color-text-weak); + padding: 0; + border: none; + font-weight: 400; + cursor: pointer; + margin-bottom: 14px; + border-radius: 0; + display: flex; + width: fit-content; + gap: 12px; + text-decoration: none; + padding-bottom: 2px; + border-bottom: 1px solid transparent; + } + + [data-slot="releases"]:hover { + background: none; + padding-bottom: 2px; + border-bottom: 1px solid var(--color-border-weak); + } + + strong { + font-size: 28px; + color: var(--color-text-strong); font-weight: 500; + margin-bottom: 16px; + + @media (max-width: 60rem) { + font-size: 22px; + } + } - } - [data-component="features"] { - border-top: 1px solid var(--color-border); - padding: var(--padding); + p { + color: var(--color-text); + margin-bottom: 24px; + max-width: 82%; - [data-slot="list"] { - padding-left: var(--space-4); - margin: 0; - list-style: disc; + @media (max-width: 50rem) { + max-width: 100%; + } + } - li { - margin-bottom: var(--space-4); - line-height: 1.6; + a { + background: var(--color-background-strong); + padding: 8px 12px 8px 20px; + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + margin-bottom: 80px; + display: flex; + width: fit-content; + gap: 12px; + text-decoration: none; + } - strong { - text-transform: uppercase; - font-weight: 600; - } + a:hover { + background: var(--color-background-strong-hover); + } + } + [data-slot="model-logos"] { + display: flex; + gap: 24px; + margin-bottom: 56px; - label { - line-height: 1; - text-transform: uppercase; - font-size: 0.75rem; - letter-spacing: 0.03125rem; - background: var(--color-border); - padding: 0.125rem 0.375rem; - color: var(--color-text-inverted); - } + svg { + color: var(--color-background-strong); + } + + @media (prefers-color-scheme: dark) { + svg { + color: var(--color-background-strong); } + } + } - li:last-child { - margin-bottom: 0; + [data-slot="pricing-copy"] { + strong { + color: var(--color-text-strong); + font-weight: 500; + } + + p:first-child { + margin-bottom: 24px; + color: var(--color-text); + display: flex; + gap: 8px; + + @media (max-width: 40rem) { + flex-direction: column; + gap: 4px; } } } - [data-component="install"] { - border-top: 1px solid var(--color-border); - display: grid; - grid-template-columns: 1fr 1fr; - grid-template-rows: 1fr 1fr; + [data-component="video"] { + border-top: 1px solid var(--color-border-weak); - @media (max-width: 40rem) { - grid-template-columns: 1fr; - grid-template-rows: auto; + video { + width: 100%; + height: auto; + max-width: none; + max-height: none; + display: block; } } - [data-component="method"] { - display: flex; - padding: calc(var(--vertical-padding) / 2) calc(var(--padding) / 2) calc(var(--vertical-padding) / 2 + 0.125rem); - flex-direction: column; - text-align: left; - gap: var(--space-2-5); + [data-slot="section-title"] { + margin-bottom: 24px; + max-width: 100%; - @media (max-width: 30rem) { - gap: 0.3125rem; + @media (max-width: 30Rem) { + margin-bottom: 0; } - @media (max-width: 40rem) { - text-align: left; + div { + display: flex; + gap: 12px; } - &:nth-child(2) { - border-left: 1px solid var(--color-border); + span { + color: var(--color-icon); + line-height: 200%; + } - @media (max-width: 40rem) { - border-left: none; - border-top: 1px solid var(--color-border); - } + h3 { + font-size: 16px; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 12px; } - &:nth-child(3) { - border-top: 1px solid var(--color-border); + p { + margin-bottom: 12px; + color: var(--color-text); } - &:nth-child(4) { - border-top: 1px solid var(--color-border); - border-left: 1px solid var(--color-border); + div > p > strong { + font-weight: 500; + color: var(--color-text-strong); + } + } - @media (max-width: 40rem) { - border-left: none; + [data-component="what"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + ul { + padding: 0; + li { + list-style: none; + margin-bottom: 16px; + display: flex; + gap: 12px; + line-height: 200%; + + span { + color: var(--color-icon); + } + strong { + font-weight: 500; + color: var(--color-text-strong); + margin-right: 12px; + } + } + li:last-child { + margin-bottom: 0; } } + } - [data-component="title"] { - letter-spacing: -0.03125rem; - text-transform: uppercase; - font-weight: normal; - font-size: 1rem; - flex-shrink: 0; - color: var(--color-text-dimmed); + [data-component="growth"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); - @media (max-width: 30rem) { - font-size: 0.75rem; + svg { + margin-top: 32px; + width: 100%; + height: 100%; + margin-left: 40px; + + @media (max-width: 60rem) { + display: none; } } - [data-slot="button"] { - all: unset; - cursor: pointer; - display: flex; - align-items: center; - color: var(--color-text-secondary); - gap: var(--space-2-5); - font-size: 1rem; + figure { + margin-top: 16px; + font-size: 13px; + margin-left: 40px; - @media (max-width: 24rem) { - font-size: 0.875rem; + span { + color: var(--color-text-strong); } - strong { - color: var(--color-text); + @media (max-width: 60rem) { + display: none; + } + } + } + + [data-component="privacy"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + + [data-slot="privacy-title"] { + h3 { + font-size: 16px; font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 12px; } - @media (max-width: 40rem) { - justify-content: flex-start; + div { + display: flex; + gap: 12px; } - @media (max-width: 30rem) { - justify-content: center; + span { + color: var(--color-icon); + line-height: 200%; } } } - [data-component="screenshots"] { - border-top: 1px solid var(--color-border); + [data-component="zen-cta"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + padding: var(--vertical-padding) var(--padding); + } - figure { - flex: 1; + [data-slot="zen-cta-copy"] { + strong { + color: var(--color-text-strong); + font-weight: 500; + margin-bottom: 16px; + display: block; + } + + p { + color: var(--color-text); + margin-bottom: 24px; + max-width: 90%; + + @media (max-width: 50rem) { + max-width: 100%; + } + } + + a { + background: var(--color-background); + padding: 8px 12px 8px 20px; + color: var(--color-text-strong); + border: none; + border-radius: 4px; + border: 1px solid var(--color-border-weak); + font-weight: 500; + cursor: pointer; display: flex; - flex-direction: column; - gap: calc(var(--padding) / 4); - padding: calc(var(--padding) / 2); - border-width: 0; - border-style: solid; - border-color: var(--color-border); - min-height: 0; - overflow: hidden; + width: fit-content; + gap: 12px; + text-decoration: none; + } - & > div, - figcaption { - display: flex; - align-items: center; + a:hover { + background: var(--color-background-weak); + } + } + [data-slot="model-logos"] { + display: flex; + gap: 24px; + margin-bottom: 40px; + + svg { + color: var(--color-background-strong); + } + + @media (prefers-color-scheme: dark) { + svg { + color: var(--color-background-strong); } + } + } - & > div { - flex: 1; - min-height: 0; - display: flex; - align-items: center; - justify-content: center; + [data-component="email"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + [data-slot="dock"] { + border-radius: 14px; + border: 0.5px solid rgba(176, 176, 176, 0.6); + background: #f2f1f0; + margin-bottom: 32px; + overflow: hidden; + height: 64px; + width: 185px; + box-shadow: + 0 6px 80px 0 rgba(0, 0, 0, 0.05), + 0 2.507px 33.422px 0 rgba(0, 0, 0, 0.04), + 0 1.34px 17.869px 0 rgba(0, 0, 0, 0.03), + 0 0.751px 10.017px 0 rgba(0, 0, 0, 0.03), + 0 0.399px 5.32px 0 rgba(0, 0, 0, 0.02), + 0 0.166px 2.214px 0 rgba(0, 0, 0, 0.01); + + img { + width: 100%; + height: auto; } - a { + @media (prefers-color-scheme: dark) { + background: #312d2d; + } + } + + [data-slot="form"] { + position: relative; + + input { + background: var(--color-background-weak); + border-radius: 6px; + border: 1px solid var(--color-border-weak); + padding: 20px; display: flex; - flex: 1; - min-height: 0; - align-items: center; - justify-content: center; + flex-direction: column; + gap: 12px; width: 100%; - height: 100%; + + @media (max-width: 30rem) { + padding-bottom: 80px; + } + } - figcaption { - letter-spacing: -0.03125rem; - text-transform: uppercase; - color: var(--color-text-dimmed); - flex-shrink: 0; + input:focus { + background: var(--color-background-interactive-weaker); + outline: none; + border: none; + color: var(--color-text-strong); + + border: 1px solid var(--color-background-strong); /* Tailwind blue-600 as example */ + + /* Tailwind-style ring */ + box-shadow: 0 0 0 3px var(--color-background-interactive); + /* mimics "ring-2 ring-blue-600/50" */ + + @media (prefers-color-scheme: dark) { + box-shadow: none; + border: 1px solid var(--color-background-interactive) + } + } + + button { + position: absolute; + height: 40px; + right: 12px; + background: var(--color-background-strong); + padding: 4px 20px; + color: var(--color-text-inverted); + border-radius: 4px; + border: none; + outline: none; + font-weight: 500; + cursor: pointer; + top: 50%; + margin-top: -20px; @media (max-width: 30rem) { - font-size: 0.75rem; + left: 20px; + right: 20px; + bottom: 20px; + top: auto; } } } + } + + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + + ul { + padding: 0; - & > [data-slot="left"] figure { - height: var(--images-height); - box-sizing: border-box; + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + } } - & > [data-slot="right"] figure { - height: calc(var(--images-height) / 2); - box-sizing: border-box; + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + align-items: start; + min-height: 24px; + + svg { + margin-top: 2px; + } + + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } } - & > [data-slot="left"] img { - width: 100%; - height: 100%; - min-width: 0; - object-fit: contain; + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + line-height: 200%; } + } - & > [data-slot="right"] img { - width: 100%; - height: calc(100% - 2rem); - object-fit: contain; - display: block; + [data-component="testimonials"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + display: flex; + flex-direction: column; + gap: 20px; + + @media (max-width: 60rem) { + --padding: 1rem; + --vertical-padding: 1rem; } - @media (max-width: 30rem) { - & { - --images-height: auto; - grid-template-columns: 1fr; - grid-template-rows: auto auto; + a { + text-decoration: none; + } + [data-slot="testimonial"] { + background: var(--color-background-weak); + border-radius: 6px; + border: 1px solid var(--color-border-weak); + padding: 20px; + display: flex; + flex-direction: column; + gap: 12px; + + @media (max-width: 60rem) { + flex-direction: column-reverse; + gap: 24px; } - & > [data-slot="left"] { - grid-row: 1; - grid-column: 1; + [data-slot="name"] { + display: flex; + gap: 16px; + + @media (max-width: 60rem) { + flex-direction: column; + gap: 8px; + } + + span { + display: inline-block; + } + + img { + height: 24px; + width: 24px; + border-radius: 24px; + } } - & > [data-slot="right"] { - grid-row: 2; - grid-column: 1; - border-left: none; - border-top: 1px solid var(--color-border); + [data-slot="quote"] { + margin-left: 40px; - & > [data-slot="row1"], - & > [data-slot="row2"] { - height: auto; + @media (max-width: 60rem) { + margin-left: 0; + } + span { + color: var(--color-text); + text-decoration: none; } } + } - & > [data-slot="left"] figure, - & > [data-slot="right"] figure { - height: auto; + [data-slot="button"] { + all: unset; + cursor: pointer; + display: flex; + align-items: center; + color: var(--color-text); + gap: var(--space-2-5); + font-size: 1rem; + + @media (max-width: 24rem) { + font-size: 0.875rem; } - & > [data-slot="left"] img, - & > [data-slot="right"] img { - width: 100%; - height: auto; - max-height: none; + strong { + color: var(--color-text-strong); + font-weight: 500; + } + + @media (max-width: 40rem) { + justify-content: flex-start; + } + + @media (max-width: 30rem) { + justify-content: center; } } } [data-component="copy-status"] { - @media (max-width: 38rem) { - display: none; - } [data-slot="copy"] { display: block; width: var(--space-4); height: var(--space-4); - color: var(--color-text-dimmed); + color: var(--color-text-weaker); [data-copied] & { display: none; @@ -452,7 +986,7 @@ display: none; width: var(--space-4); height: var(--space-4); - color: var(--color-text); + color: var(--color-text-strong); [data-copied] & { display: block; @@ -461,44 +995,71 @@ } [data-component="footer"] { - border-top: 1px solid var(--color-border); + border-top: 1px solid var(--color-border-weak); display: flex; flex-direction: row; + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + [data-slot="cell"] { flex: 1; text-align: center; - text-transform: uppercase; - padding: var(--vertical-padding) 0.5rem; + + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: var(--space-1); + text-decoration-thickness: 1px; + } } [data-slot="cell"] + [data-slot="cell"] { - border-left: 1px solid var(--color-border); + border-left: 1px solid var(--color-border-weak); } /* Mobile: third column on its own row */ - @media (max-width: 30rem) { + @media (max-width: 25rem) { flex-wrap: wrap; - [data-slot="cell"]:nth-child(1), - [data-slot="cell"]:nth-child(2) { - flex: 1; - } - - [data-slot="cell"]:nth-child(3) { + [data-slot="cell"] { flex: 1 0 100%; border-left: none; - border-top: 1px solid var(--color-border); + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; } } } [data-component="legal"] { - color: var(--color-text-dimmed); + color: var(--color-text-weak); text-align: center; a { - color: var(--color-text-dimmed); + color: var(--color-text-weak); + text-decoration: none; } } } diff --git a/packages/console/app/src/routes/index.tsx b/packages/console/app/src/routes/index.tsx index 3d663c27e..6687cf87a 100644 --- a/packages/console/app/src/routes/index.tsx +++ b/packages/console/app/src/routes/index.tsx @@ -1,14 +1,21 @@ import "./index.css" -import { Title } from "@solidjs/meta" -import { onCleanup, onMount } from "solid-js" -import logoLight from "../asset/logo-ornate-light.svg" -import logoDark from "../asset/logo-ornate-dark.svg" -import IMG_SPLASH from "../asset/lander/screenshot-splash.png" +import { Title, Meta, Link } from "@solidjs/meta" +import { HttpHeader } from "@solidjs/start" +import video from "../asset/lander/opencode-min.mp4" +import videoPoster from "../asset/lander/opencode-poster.png" import { IconCopy, IconCheck } from "../component/icon" -import { createAsync, query } from "@solidjs/router" +import { A, createAsync, query } from "@solidjs/router" import { getActor } from "~/context/auth" import { withActor } from "~/context/auth.withActor" import { Account } from "@opencode/console-core/account.js" +import { EmailSignup } from "~/component/email-signup" +import { Tabs } from "@kobalte/core/tabs" +import { Faq } from "~/component/faq" +import { Header } from "~/component/header" +import { Footer } from "~/component/footer" +import { Legal } from "~/component/legal" +import { github } from "~/lib/github" +import { createMemo } from "solid-js" function CopyStatus() { return ( @@ -19,6 +26,7 @@ function CopyStatus() { ) } + const defaultWorkspace = query(async () => { "use server" const actor = await getActor() @@ -29,155 +37,1106 @@ const defaultWorkspace = query(async () => { }, "defaultWorkspace") export default function Home() { + const githubData = createAsync(() => github()) const workspace = createAsync(() => defaultWorkspace()) - onMount(() => { - const commands = document.querySelectorAll("[data-copy]") - for (const button of commands) { - const callback = () => { - const text = button.textContent - if (text) { - navigator.clipboard.writeText(text) - button.setAttribute("data-copied", "") - setTimeout(() => { - button.removeAttribute("data-copied") - }, 1500) - } - } - button.addEventListener("click", callback) - onCleanup(() => { - button.removeEventListener("click", callback) - }) + const release = createMemo(() => githubData()?.release) + + const handleCopyClick = (event: Event) => { + const button = event.currentTarget as HTMLButtonElement + const text = button.textContent + if (text) { + navigator.clipboard.writeText(text) + button.setAttribute("data-copied", "") + setTimeout(() => { + button.removeAttribute("data-copied") + }, 1500) } - }) + } + return ( -
- opencode | AI coding agent built for the terminal - -
-
- opencode logo light - opencode logo dark -

The AI coding agent built for the terminal

- -
- -
- - -
- -
-
- -
-
    -
  • - Native TUI A responsive, native, themeable terminal UI -
  • -
  • - LSP enabled Automatically loads the right LSPs for the LLM -
  • -
  • - opencode zen A curated list of models provided by opencode{" "} - -
  • -
  • - Multi-session Start multiple agents in parallel on the same project -
  • -
  • - Shareable links Share a link to any sessions for reference or to debug -
  • -
  • - Claude Pro Log in with Anthropic to use your Claude Pro or Max account -
  • -
  • - Use any model Supports 75+ LLM providers through{" "} - Models.dev, including local models -
  • -
-
- -
-
-

npm

- -
-
-

bun

- -
-
-

homebrew

- -
-
-

paru

- -
-
- -
-
-
opencode TUI with the tokyonight theme
- - opencode TUI with tokyonight theme - -
-
- - -
+
+ + OpenCode | The AI coding agent built for the terminal + + + +
+
+ +
+
+
+ + What’s new in {release()?.name ?? "the latest release"} + + The AI coding agent built for the terminal +

+ OpenCode is fully open source, giving you control and freedom to use any provider, any model, and any + editor. +

+ + Read docs + + + + +
+
+ + + + curl + + + npm + + + bun + + + brew + + + paru + + + +
+ + + + + + + + + + + + + + + +
+
+
+
+ +
+ +
+ +
+
+

What is OpenCode?

+

OpenCode is an open source agent that helps you write and run code directly from the terminal.

+
+
    +
  • + [*] +
    + Native TUI A responsive, native, themeable terminal UI +
    +
  • +
  • + [*] +
    + LSP enabled Automatically loads the right LSPs for the LLM +
    +
  • +
  • + [*] +
    + Multi-session Start multiple agents in parallel on the same project +
    +
  • +
  • + [*] +
    + Share links Share a link to any session for reference or to debug +
    +
  • +
  • + [*] +
    + Claude Pro Log in with Anthropic to use your Claude Pro or Max account +
    +
  • +
  • + [*] +
    + Any model 75+ LLM providers through Models.dev, including local models +
    +
  • +
  • + [*] +
    + Any editor OpenCode runs in your terminal, pair it with any IDE +
    +
  • +
+
+ +
+
+

The open source AI coding agent

+
+ [*] +

+ With over 26,000 GitHub + stars, 188 contributors, and almost{" "} + 3,000 commits, OpenCode is used and trusted + by over 200,000{" "} + developers every month. +

+
+ +
+
+
+ + + + + + + + + + + + + + + + + + + + + +
+
Fig 1.
26K GitHub Stars
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Fig 2.
188 Contributors
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
Fig 3.
200K Monthly Devs
+
+
+ + +
+
+ +
+
+

Built for privacy first

+
+ [*] + +

+ OpenCode does not store any of your code or context data, so + that it can operate in privacy sensitive + environments. Learn more about privacy + and enterprise. +

+
+
+
+ +
+
+

FAQ

+
+
    +
  • + + OpenCode is an open source agent that helps you write and run + code directly from the terminal. You can + pair OpenCode with any AI model, and because it’s + terminal-based you can pair it with your preferred + code editor. + +
  • +
  • + + The easiest way to get started is to read the intro. + +
  • +
  • + + Not necessarily, but probably. You’ll need an AI subscription + if you want to connect OpenCode to a + paid provider, although you can work with{" "} + + local models + {" "} + for free. While we encourage users to use Zen, OpenCode works with all popular + providers such as OpenAI, Anthropic, xAI etc. + +
  • +
  • + + Yes, for now. We are actively working on a desktop app. Join + the waitlist for early access. + +
  • +
  • + + OpenCode is 100% free to use. Any additional costs will come + from your subscription to a model + provider. While OpenCode works with any model provider, we + recommend using Zen. + +
  • +
  • + + Your data and information is only stored when you create + sharable links in OpenCode. Learn more about{" "} + share pages. + +
  • +
  • + + Yes, OpenCode is fully open source. The source code is public + on{" "} + + GitHub + {" "} + under the{" "} + + MIT License + + , meaning anyone can use, modify, or contribute to its + development. Anyone from the community can file + issues, submit pull requests, and extend functionality. + +
  • +
+
+ +
+
+ Access reliable optimized models for coding + agents +

+ Zen gives you access to a handpicked set of AI models that + OpenCode has tested and benchmarked + specifically for coding agents. No need to worry about + inconsistent performance and quality across + providers, use validated models that work. +

+
+
+ + + + + + + + +
+
+ + + + +
+
+ + + + +
+
+ + + +
+
+ + + +
+
+ + Learn about Zen + + + + +
+
-
- - ©2025 Anomaly - + +
+
+
) } diff --git a/packages/console/app/src/routes/temp.tsx b/packages/console/app/src/routes/temp.tsx new file mode 100644 index 000000000..3d663c27e --- /dev/null +++ b/packages/console/app/src/routes/temp.tsx @@ -0,0 +1,183 @@ +import "./index.css" +import { Title } from "@solidjs/meta" +import { onCleanup, onMount } from "solid-js" +import logoLight from "../asset/logo-ornate-light.svg" +import logoDark from "../asset/logo-ornate-dark.svg" +import IMG_SPLASH from "../asset/lander/screenshot-splash.png" +import { IconCopy, IconCheck } from "../component/icon" +import { createAsync, query } from "@solidjs/router" +import { getActor } from "~/context/auth" +import { withActor } from "~/context/auth.withActor" +import { Account } from "@opencode/console-core/account.js" + +function CopyStatus() { + return ( +
+ + +
+ ) +} + +const defaultWorkspace = query(async () => { + "use server" + const actor = await getActor() + if (actor.type === "account") { + const workspaces = await withActor(() => Account.workspaces()) + return workspaces[0].id + } +}, "defaultWorkspace") + +export default function Home() { + const workspace = createAsync(() => defaultWorkspace()) + onMount(() => { + const commands = document.querySelectorAll("[data-copy]") + for (const button of commands) { + const callback = () => { + const text = button.textContent + if (text) { + navigator.clipboard.writeText(text) + button.setAttribute("data-copied", "") + setTimeout(() => { + button.removeAttribute("data-copied") + }, 1500) + } + } + button.addEventListener("click", callback) + onCleanup(() => { + button.removeEventListener("click", callback) + }) + } + }) + + return ( +
+ opencode | AI coding agent built for the terminal + +
+
+ opencode logo light + opencode logo dark +

The AI coding agent built for the terminal

+ +
+ +
+ + +
+ +
+
+ +
+
    +
  • + Native TUI A responsive, native, themeable terminal UI +
  • +
  • + LSP enabled Automatically loads the right LSPs for the LLM +
  • +
  • + opencode zen A curated list of models provided by opencode{" "} + +
  • +
  • + Multi-session Start multiple agents in parallel on the same project +
  • +
  • + Shareable links Share a link to any sessions for reference or to debug +
  • +
  • + Claude Pro Log in with Anthropic to use your Claude Pro or Max account +
  • +
  • + Use any model Supports 75+ LLM providers through{" "} + Models.dev, including local models +
  • +
+
+ +
+
+

npm

+ +
+
+

bun

+ +
+
+

homebrew

+ +
+
+

paru

+ +
+
+ +
+
+
opencode TUI with the tokyonight theme
+ + opencode TUI with tokyonight theme + +
+
+ + +
+ +
+ + ©2025 Anomaly + +
+
+ ) +} diff --git a/packages/console/app/src/routes/zen/index.css b/packages/console/app/src/routes/zen/index.css new file mode 100644 index 000000000..3856bd14b --- /dev/null +++ b/packages/console/app/src/routes/zen/index.css @@ -0,0 +1,781 @@ +::selection { + background: var(--color-background-interactive); + color: var(--color-text-strong); + + @media (prefers-color-scheme: dark) { + background: var(--color-background-interactive); + color: var(--color-text-inverted); + } +} + +[data-page="zen"] { + --color-background: hsl(0, 20%, 99%); + --color-background-weak: hsl(0, 8%, 97%); + --color-background-strong: hsl(0, 5%, 12%); + --color-background-strong-hover: hsl(0, 5%, 18%); + --color-background-interactive: hsl(62, 84%, 88%); + --color-background-interactive-weaker: hsl(64, 74%, 95%); + + --color-text: hsl(0, 1%, 39%); + --color-text-weak: hsl(0, 1%, 74%); + --color-text-weaker: hsl(30, 2%, 81%); + --color-text-strong: hsl(0, 5%, 12%); + --color-text-inverted: hsl(0, 20%, 99%); + + --color-border: hsl(30, 2%, 81%); + --color-border-weak: hsl(0, 1%, 85%); + + --color-icon: hsl(0, 1%, 55%); +} + +[data-page="zen"] { + @media (prefers-color-scheme: dark) { + --color-background: hsl(0, 9%, 7%); + --color-background-weak: hsl(0, 6%, 10%); + --color-background-strong: hsl(0, 15%, 94%); + --color-background-strong-hover: hsl(0, 15%, 97%); + --color-background-interactive: hsl(62, 100%, 90%); + --color-background-interactive-weaker: hsl(60, 20%, 8%); + + --color-text: hsl(0, 4%, 71%); + --color-text-weak: hsl(0, 2%, 49%); + --color-text-weaker: hsl(0, 3%, 28%); + --color-text-strong: hsl(0, 15%, 94%); + --color-text-inverted: hsl(0, 9%, 7%); + + --color-border: hsl(0, 3%, 28%); + --color-border-weak: hsl(0, 4%, 23%); + + --color-icon: hsl(10, 3%, 43%); + } +} + +[data-page="zen"] { + background: var(--color-background); + --padding: 5rem; + --vertical-padding: 4rem; + border-top: 1px solid var(--color-border-weak); + + @media (max-width: 60rem) { + --padding: 1.5rem; + --vertical-padding: 3rem; + } + + display: flex; + gap: var(--vertical-padding); + flex-direction: column; + font-family: var(--font-mono); + color: var(--color-text); + padding-bottom: 5rem; + + a { + color: var(--color-text-strong); + text-decoration: underline; + text-underline-offset: var(--space-1); + text-decoration-thickness: 1px; + } + + p { + line-height: 200%; + } + + @media (max-width: 60rem) { + font-size: 15px; + } + + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + input:-webkit-autofill:active { + transition: background-color 5000000s ease-in-out 0s; + } + + + [data-component="container"] { + max-width: 67.5rem; + margin: 0 auto; + border: 1px solid var(--color-border-weak); + border-top: none; + + @media (max-width: 65rem) { + border: none; + } + } + + [data-component="content"] { + } + + [data-component="top"] { + padding: 24px var(--padding); + height: 80px; + position: sticky; + top: 0; + display: flex; + justify-content: space-between; + align-items: center; + background: var(--color-background); + border-bottom: 1px solid var(--color-border-weak); + + z-index: 10; + + img { + height: 34px; + width: auto; + } + + [data-component="nav-desktop"] { + ul { + display: flex; + justify-content: space-between; + gap: 48px; + li { + display: inline-block; + a { + text-decoration: none; + span { + color: var(--color-text-weak); + } + } + a:hover { + text-decoration: underline; + text-underline-offset: var(--space-1); + text-decoration-thickness: 1px; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile-toggle"] { + border: none; + background: none; + outline: none; + height: 40px; + width: 40px; + cursor: pointer; + } + + [data-component="nav-mobile-toggle"]:hover { + background: var(--color-background-weak); + } + + [data-component="nav-mobile"] { + display: none; + + @media (max-width: 40rem) { + display: block; + + [data-component="nav-mobile-icon"] { + cursor: pointer; + height: 40px; + width: 40px; + display: flex; + align-items: center; + justify-content: center; + } + + [data-component="nav-mobile-menu-list"] { + position: fixed; + background: var(--color-background); + top: 80px; + left: 0; + right: 0; + height: 100vh; + + ul { + list-style: none; + padding: 20px 0; + + li { + a { + text-decoration: none; + padding: 20px; + display: block; + + span { + color: var(--color-text-weak); + } + } + + a:hover { + background: var(--color-background-weak); + } + } + } + } + } + } + + [data-slot="logo dark"] { + display: none; + } + + @media (prefers-color-scheme: dark) { + [data-slot="logo light"] { + display: none; + } + [data-slot="logo dark"] { + display: block; + } + } + } + + [data-component="hero"] { + display: flex; + flex-direction: column; + padding: calc(var(--vertical-padding)*2) var(--padding); + + [data-slot="zen logo dark"] { + display: none; + } + + @media (max-width: 30rem) { + padding: var(--vertical-padding) var(--padding) + } + + @media (prefers-color-scheme: dark) { + [data-slot="zen logo light"] { + display: none; + } + [data-slot="zen logo dark"] { + display: block; + } + } + } + + [data-slot="hero-copy"] { + img { + margin-bottom: 24px; + } + + strong { + font-size: 28px; + color: var(--color-text-strong); + font-weight: 500; + margin-bottom: 16px; + display: block; + + @media (max-width: 60rem) { + font-size: 22px; + } + } + + + + p { + color: var(--color-text); + margin-bottom: 24px; + max-width: 82%; + + @media (max-width: 50rem) { + max-width: 100%; + } + } + + a { + background: var(--color-background-strong); + padding: 8px 12px 8px 20px; + color: var(--color-text-inverted); + border: none; + border-radius: 4px; + font-weight: 500; + cursor: pointer; + margin-bottom: 56px; + display: flex; + width: fit-content; + gap: 12px; + text-decoration: none; + } + + a:hover { + background: var(--color-background-strong-hover); + } + } + [data-slot="model-logos"] { + display: flex; + gap: 24px; + margin-bottom: 56px; + + svg { + color: var(--color-background-strong); + } + + @media (prefers-color-scheme: dark) { + svg { + color: var(--color-background-strong); + } + } + } + + [data-slot="pricing-copy"] { + strong { + color: var(--color-text-strong); + font-weight: 500; + } + + p:first-child { + margin-bottom: 24px; + color: var(--color-text); + display: flex; + gap: 8px; + + @media (max-width: 40rem) { + flex-direction: column; + gap: 4px; + } + } + } + + [data-component="comparison"] { + border-top: 1px solid var(--color-border-weak); + video { + width: 100%; + height: auto; + max-width: none; + max-height: none; + display: block; + } + } + + [data-slot="section-title"] { + margin-bottom: 24px; + + h3 { + font-size: 16px; + font-weight: 500; + color: var(--color-text-strong); + margin-bottom: 12px; + } + + p { + margin-bottom: 12px; + color: var(--color-text); + } + } + + [data-component="problem"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + p { + margin-bottom: 24px; + } + + ul { + padding: 0; + li { + list-style: none; + margin-bottom: 16px; + display: flex; + gap: 12px; + + span { + color: var(--color-icon); + } + } + li:last-child { + margin-bottom: 0; + } + } + } + + [data-component="how"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + ul { + padding: 0; + li { + list-style: none; + margin-bottom: 16px; + display: flex; + gap: 12px; + + span { + color: var(--color-icon); + } + strong { + font-weight: 500; + color: var(--color-text-strong); + } + } + li:last-child { + margin-bottom: 0; + } + } + } + + [data-component="privacy"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + [data-slot="privacy-title"] { + h3 { + font-size: 16px; + font-weight: 500; + color: var(--color-text); + margin-bottom: 12px; + } + + div { + display: flex; + gap: 12px; + } + + p { + } + + span { + color: var(--color-icon); + line-height: 200%; + } + + div { + display: flex; + gap: 12px; + } + } + } + + [data-component="email"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + color: var(--color-text); + + [data-slot="dock"] { + border-radius: 14px; + border: 0.5px solid rgba(176, 176, 176, 0.6); + background: #f2f1f0; + margin-bottom: 32px; + overflow: hidden; + height: 64px; + width: 185px; + box-shadow: + 0 6px 80px 0 rgba(0, 0, 0, 0.05), + 0 2.507px 33.422px 0 rgba(0, 0, 0, 0.04), + 0 1.34px 17.869px 0 rgba(0, 0, 0, 0.03), + 0 0.751px 10.017px 0 rgba(0, 0, 0, 0.03), + 0 0.399px 5.32px 0 rgba(0, 0, 0, 0.02), + 0 0.166px 2.214px 0 rgba(0, 0, 0, 0.01); + + img { + width: 100%; + height: auto; + } + + @media (prefers-color-scheme: dark) { + background: #312d2d; + } + } + + [data-slot="form"] { + position: relative; + + input { + background: var(--color-background-weak); + border-radius: 6px; + border: 1px solid var(--color-border-weak); + padding: 20px; + display: flex; + flex-direction: column; + gap: 12px; + width: 100%; + + @media (max-width: 30rem) { + padding-bottom: 80px; + } + } + + input:focus { + background: var(--color-background-interactive-weaker); + outline: none; + border: none; + color: var(--color-text-strong); + + border: 1px solid var(--color-background-strong); /* Tailwind blue-600 as example */ + + /* Tailwind-style ring */ + box-shadow: 0 0 0 3px var(--color-background-interactive); + /* mimics "ring-2 ring-blue-600/50" */ + } + + button { + position: absolute; + height: 40px; + right: 12px; + background: var(--color-background-strong); + padding: 4px 20px; + color: var(--color-text-inverted); + border-radius: 4px; + font-weight: 500; + cursor: pointer; + top: 50%; + margin-top: -20px; + + @media (max-width: 30rem) { + left: 20px; + right: 20px; + bottom: 20px; + top: auto; + } + } + } + } + + [data-component="faq"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + + ul { + padding: 0; + + li { + list-style: none; + margin-bottom: 24px; + line-height: 200%; + } + } + + [data-slot="faq-question"] { + display: flex; + gap: 16px; + margin-bottom: 8px; + color: var(--color-text-strong); + font-weight: 500; + cursor: pointer; + background: none; + border: none; + padding: 0; + + [data-slot="faq-icon-plus"] { + flex-shrink: 0; + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + [data-closed] & { + display: none; + } + [data-expanded] & { + display: block; + } + } + [data-slot="faq-question-text"] { + flex-grow: 1; + text-align: left; + } + } + + [data-slot="faq-answer"] { + margin-left: 40px; + margin-bottom: 32px; + } + } + + [data-component="testimonials"] { + border-top: 1px solid var(--color-border-weak); + padding: var(--vertical-padding) var(--padding); + display: flex; + flex-direction: column; + gap: 20px; + + @media (max-width: 60rem) { + --padding: 1rem; + --vertical-padding: 1rem; + } + + a { + text-decoration: none; + } + [data-slot="testimonial"] { + background: var(--color-background-weak); + border-radius: 6px; + border: 1px solid var(--color-border-weak); + padding: 20px; + display: flex; + flex-direction: column; + gap: 12px; + + @media (max-width: 60rem) { + flex-direction: column-reverse; + gap: 24px; + padding: 24px 48px; + } + + [data-slot="name"] { + display: flex; + gap: 16px; + + strong { + font-weight: 500; + } + + span { + color: var(--color-text); + } + + @media (max-width: 60rem) { + flex-direction: column; + gap: 8px; + } + + span { + display: inline-block; + } + + img { + height: 24px; + width: 24px; + border-radius: 24px; + } + } + + [data-slot="quote"] { + margin-left: 40px; + + @media (max-width: 60rem) { + margin-left: 0; + } + span { + color: var(--color-text); + text-decoration: none; + } + } + } + + [data-slot="button"] { + all: unset; + cursor: pointer; + display: flex; + align-items: center; + color: var(--color-text); + gap: var(--space-2-5); + font-size: 1rem; + + @media (max-width: 24rem) { + font-size: 0.875rem; + } + + strong { + color: var(--color-text-strong); + font-weight: 500; + } + + @media (max-width: 40rem) { + justify-content: flex-start; + } + + @media (max-width: 30rem) { + justify-content: center; + } + } + } + + [data-component="copy-status"] { + @media (max-width: 38rem) { + display: none; + } + + [data-slot="copy"] { + display: block; + width: var(--space-4); + height: var(--space-4); + color: var(--color-text-weaker); + + [data-copied] & { + display: none; + } + } + + [data-slot="check"] { + display: none; + width: var(--space-4); + height: var(--space-4); + color: var(--color-text-strong); + + [data-copied] & { + display: block; + } + } + } + + [data-component="footer"] { + border-top: 1px solid var(--color-border-weak); + display: flex; + flex-direction: row; + + @media (max-width: 65rem) { + border-bottom: 1px solid var(--color-border-weak); + } + + + [data-slot="cell"] { + flex: 1; + text-align: center; + + + a { + text-decoration: none; + padding: 2rem 0; + width: 100%; + display: block; + + span { + color: var(--color-text-weak); + + @media (max-width: 40rem) { + display: none; + } + + } + } + + a:hover { + background: var(--color-background-weak); + text-decoration: underline; + text-underline-offset: var(--space-1); + text-decoration-thickness: 1px; + } + } + + [data-slot="cell"] + [data-slot="cell"] { + border-left: 1px solid var(--color-border-weak); + } + + /* Mobile: third column on its own row */ + @media (max-width: 25rem) { + flex-wrap: wrap; + + [data-slot="cell"] { + flex: 1 0 100%; + border-left: none; + border-top: 1px solid var(--color-border-weak); + } + + [data-slot="cell"]:nth-child(1) { + border-top: none; + } + } + } + + [data-component="legal"] { + color: var(--color-text-weak); + text-align: center; + + a { + color: var(--color-text-weak); + text-decoration: none; + } + } +} diff --git a/packages/console/app/src/routes/zen/index.tsx b/packages/console/app/src/routes/zen/index.tsx new file mode 100644 index 000000000..a676471d4 --- /dev/null +++ b/packages/console/app/src/routes/zen/index.tsx @@ -0,0 +1,339 @@ +import "./index.css" +import { Title, Meta, Link } from "@solidjs/meta" +import { HttpHeader } from "@solidjs/start" +import zenLogoLight from "../../asset/zen-ornate-light.svg" +import zenLogoDark from "../../asset/zen-ornate-dark.svg" +import compareVideo from "../../asset/lander/opencode-comparison-min.mp4" +import compareVideoPoster from "../../asset/lander/opencode-comparison-poster.png" +import avatarDax from "../../asset/lander/avatar-dax.png" +import avatarJay from "../../asset/lander/avatar-Jay.png" +import avatarFrank from "../../asset/lander/avatar-Frank.png" +import avatarAdam from "../../asset/lander/avatar-Adam.png" +import avatarDavid from "../../asset/lander/avatar-David.png" +import { A, createAsync, query } from "@solidjs/router" +import { getActor } from "~/context/auth" +import { withActor } from "~/context/auth.withActor" +import { Account } from "@opencode/console-core/account.js" +import { EmailSignup } from "~/component/email-signup" +import { Faq } from "~/component/faq" +import { Legal } from "~/component/legal" +import { Footer } from "~/component/footer" +import { Header } from "~/component/header" + +const defaultWorkspace = query(async () => { + "use server" + const actor = await getActor() + if (actor.type === "account") { + const workspaces = await withActor(() => Account.workspaces()) + return workspaces[0].id + } +}, "defaultWorkspace") + +export default function Home() { + const workspace = createAsync(() => defaultWorkspace()) + + return ( +
+ + OpenCode Zen | A curated set of reliable optimized models for coding agents + + + + +
+
+ +
+
+
+ zen logo light + zen logo dark + Reliable optimized models for coding agents +

+ Zen gives you access to a curated set of AI models that OpenCode has tested and benchmarked specifically + for coding agents. No need to worry about inconsistent performance and quality, use validated models + that work. +

+
+
+ + + + + + + + +
+
+ + + + +
+
+ + + + +
+
+ + + +
+
+ + + +
+
+ + Get started with Zen + + + + +
+
+

+ Add $20 Pay as you go balance (+$1.23 card processing fee) +

+

Use with any agent. Set monthly spend limits. Cancel any time.

+
+
+ +
+ +
+ +
+
+

What problem is Zen solving?

+

+ There are so many models available, but only a few work well with coding agents. +
+ Most providers configure them differently with varying results. +

+
+

We're fixing this for everyone, not just OpenCode users.

+
    +
  • + [*] Testing select models and consulting their teams +
  • +
  • + [*] Working with providers to ensure they’re delivered properly +
  • +
  • + [*] Benchmarking all model-provider combinations we recommend +
  • +
+
+ +
+
+

How Zen works

+

While we suggest you use Zen with OpenCode, you can use Zen with any agent.

+
+
    +
  • + [1] +
    + Sign up and add $20 balance - follow the{" "} + + setup instructions + +
    +
  • +
  • + [2] +
    + Use Zen with transparent pricing - pay per request with zero markups +
    +
  • +
  • + [3] +
    + Auto-top up - when your balance reaches $5 we’ll automatically add $20 +
    +
  • +
+
+ +
+
+

Your privacy is important to us

+
+ [*] +

+ All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions. +

+
+
+
+ +
+ {/*Dax*/} + +
+
+ + Dax Raad + ex-CEO, Terminal Products +
+
+ It's clear from using @OpenCode Zen that the team behind it are smart, funny, and + excellent lovers. +
+
+
+ {/*Jay*/} + +
+
+ + Jay V + ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint +
+
+ 4 out 5 people on our team love using @OpenCode Zen. +
+
+
+ {/*Adam*/} + +
+
+ + Adam Elmore + ex-Hero, AWS +
+
+ I can't recommend @OpenCode Zen enough. Seriously, it’s really good. +
+
+
+ {/*David*/} + +
+
+ + David Hill + ex-Head of Design, Laravel +
+
+ With @OpenCode Zen I know all the models are tested and perfect for coding agents. +
+
+
+ {/*Frank*/} + +
+
+ + Frank Wang + ex-Intern, Nvidia (4 times) +
+
I wish I was still at Nvidia.
+
+
+
+ +
+
+

FAQ

+
+
    +
  • + + Zen is a curated set of AI models tested and benchmarked for coding agents created by the team behind + OpenCode. + +
  • +
  • + + Zen only provides models that have been specifically tested and benchmarked for coding agents. You + wouldn’t use a butter knife to cut steak, don’t use poor models for coding. + +
  • +
  • + + Zen is not for profit. Zen passes through the costs from the model providers to you. The higher Zen’s + usage the more OpenCode can negotiate better rates and pass those to you. + +
  • +
  • + + Zen charges per request with zero markups, so you pay exactly what the model provider charges. Your + total cost depends on usage, and you can set monthly spend limits in your account. + To cover costs, OpenCode adds only a small payment processing fee of $1.23 per $20 balance top-up. + +
  • +
  • + + All Zen models are hosted in the US. Providers follow a zero-retention policy and do not use your data + for model training, with the following exceptions. + +
  • +
  • + Yes, you can set monthly spending limits in your account. +
  • +
  • + + Yes, you can disable billing at any time and use your remaining balance. + +
  • +
  • + + While Zen works great with OpenCode, you can use Zen with any agent. Follow the setup instructions in + your preferred coding agent. + +
  • +
+
+ + +
+
+
+ + +
+ ) +} diff --git a/packages/console/app/src/style/base.css b/packages/console/app/src/style/base.css index a4847ed43..1c3f1d55b 100644 --- a/packages/console/app/src/style/base.css +++ b/packages/console/app/src/style/base.css @@ -7,3 +7,15 @@ html { body { font-family: var(--font-sans); } + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} -- cgit v1.2.3