From 3c8ce4ab90faf4d8ea62724a73322e6330701e5c Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 3 Mar 2026 18:29:42 +0000 Subject: [PATCH 01/32] feat(console): add /go landing page --- .../console/app/script/generate-sitemap.ts | 1 + packages/console/app/src/routes/go/index.css | 867 ++++++++++++++++++ packages/console/app/src/routes/go/index.tsx | 337 +++++++ 3 files changed, 1205 insertions(+) create mode 100644 packages/console/app/src/routes/go/index.css create mode 100644 packages/console/app/src/routes/go/index.tsx diff --git a/packages/console/app/script/generate-sitemap.ts b/packages/console/app/script/generate-sitemap.ts index bdce205b9..89bca6bac 100755 --- a/packages/console/app/script/generate-sitemap.ts +++ b/packages/console/app/script/generate-sitemap.ts @@ -26,6 +26,7 @@ async function getMainRoutes(): Promise { { path: "/enterprise", priority: 0.8, changefreq: "weekly" }, { path: "/brand", priority: 0.6, changefreq: "monthly" }, { path: "/zen", priority: 0.8, changefreq: "weekly" }, + { path: "/go", priority: 0.8, changefreq: "weekly" }, ] for (const item of staticRoutes) { diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css new file mode 100644 index 000000000..7069f3f21 --- /dev/null +++ b/packages/console/app/src/routes/go/index.css @@ -0,0 +1,867 @@ +::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="go"] { + --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="go"] { + @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%); + } +} + +body { + background: var(--color-background); +} + +@supports (background: -webkit-named-image(i)) { + [data-page="opencode"] { + border-top: 1px solid var(--color-border-weak); + } +} + +[data-page="go"] { + background: var(--color-background); + --padding: 5rem; + --vertical-padding: 4rem; + + @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) { + line-height: 180%; + } + } + + @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; + } + + input:-webkit-autofill { + -webkit-text-fill-color: var(--color-text-strong) !important; + } + + input:-moz-autofill { + -moz-text-fill-color: var(--color-text-strong) !important; + } + + [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; + align-items: center; + gap: 48px; + + @media (max-width: 55rem) { + gap: 32px; + } + + @media (max-width: 48rem) { + gap: 24px; + } + 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; + } + [data-slot="cta-button"] { + background: var(--color-background-strong); + color: var(--color-text-inverted); + padding: 8px 16px; + border-radius: 4px; + font-weight: 500; + text-decoration: none; + white-space: nowrap; + + @media (max-width: 55rem) { + display: none; + } + } + [data-slot="cta-button"]:hover { + background: var(--color-background-strong-hover); + text-decoration: none; + } + } + } + + @media (max-width: 40rem) { + display: none; + } + } + + [data-component="nav-mobile"] { + button > svg { + color: var(--color-icon); + } + } + + [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; + } + + h1 { + font-size: 28px; + color: var(--color-text-strong); + font-weight: 700; + 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: 700; + 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: 700; + color: var(--color-text); + margin-bottom: 12px; + } + + div { + display: flex; + gap: 12px; + } + + p { + } + + span { + color: var(--color-icon); + line-height: 200%; + + @media (max-width: 60rem) { + line-height: 180%; + } + } + + 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; + width: 100%; + + /* Use color, not -moz-text-fill-color, for normal text */ + color: var(--color-text-strong); + + @media (max-width: 30rem) { + padding-bottom: 80px; + } + + &:not(:focus) { + color: var(--color-text-strong); + } + + &::placeholder { + color: var(--color-text-weak); + opacity: 1; + } + + /* Optional legacy */ + &::-moz-placeholder { + color: var(--color-text-weak); + opacity: 1; + } + } + + 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; + border: none; + outline: none; + 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%; + + @media (max-width: 60rem) { + line-height: 180%; + } + } + } + + [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; + color: var(--color-text-weak); + margin-top: 2px; + + [data-closed] & { + display: block; + } + [data-expanded] & { + display: none; + } + } + [data-slot="faq-icon-minus"] { + flex-shrink: 0; + color: var(--color-text-weak); + margin-top: 2px; + + [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; + + 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: 30rem) { + flex-direction: column-reverse; + gap: 24px; + } + + [data-slot="name"] { + display: flex; + gap: 16px; + + strong { + font-weight: 500; + flex: 0 0 auto; + } + + span { + color: var(--color-text); + } + + @media (max-width: 30rem) { + 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: 30rem) { + 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); + + @media (max-width: 40rem) { + border-left: none; + } + } + + /* 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; + display: flex; + gap: 32px; + justify-content: center; + + a { + color: var(--color-text-weak); + text-decoration: none; + } + + a:hover { + color: var(--color-text); + text-decoration: underline; + } + } +} diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx new file mode 100644 index 000000000..38b44bf79 --- /dev/null +++ b/packages/console/app/src/routes/go/index.tsx @@ -0,0 +1,337 @@ +import "./index.css" +import { createAsync, query, redirect } from "@solidjs/router" +import { Title, Meta } 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 { 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" +import { getLastSeenWorkspaceID } from "../workspace/common" +import { IconGemini, IconMiniMax, IconZai } from "~/component/icon" +import { useI18n } from "~/context/i18n" +import { useLanguage } from "~/context/language" +import { LocaleLinks } from "~/component/locale-links" + +const checkLoggedIn = query(async () => { + "use server" + const workspaceID = await getLastSeenWorkspaceID().catch(() => {}) + if (workspaceID) throw redirect(`/workspace/${workspaceID}`) +}, "checkLoggedIn.get") + +export default function Home() { + const loggedin = createAsync(() => checkLoggedIn()) + const i18n = useI18n() + const language = useLanguage() + return ( +
+ {/**/} + {i18n.t("zen.title")} + + + + + +
+
+ +
+
+
+ + +

{i18n.t("zen.hero.title")}

+

{i18n.t("zen.hero.body")}

+
+
+ + + + + + + + +
+
+ + + + +
+
+ +
+
+ + + + +
+
+ +
+
+ + + +
+
+ +
+
+ + + +
+
+ + {i18n.t("zen.cta.start")} + + + + +
+
+

+ {i18n.t("zen.pricing.title")} {i18n.t("zen.pricing.fee")} +

+

{i18n.t("zen.pricing.body")}

+
+
+ +
+ +
+ +
+
+

{i18n.t("zen.problem.title")}

+

{i18n.t("zen.problem.body")}

+
+

{i18n.t("zen.problem.subtitle")}

+
    +
  • + [*] {i18n.t("zen.problem.item1")} +
  • +
  • + [*] {i18n.t("zen.problem.item2")} +
  • +
  • + [*] {i18n.t("zen.problem.item3")} +
  • +
+
+ +
+
+

{i18n.t("zen.how.title")}

+

{i18n.t("zen.how.body")}

+
+
    +
  • + [1] +
    + {i18n.t("zen.how.step1.title")} - {i18n.t("zen.how.step1.beforeLink")}{" "} + + {i18n.t("zen.how.step1.link")} + +
    +
  • +
  • + [2] +
    + {i18n.t("zen.how.step2.title")} -{" "} + {i18n.t("zen.how.step2.link")}{" "} + {i18n.t("zen.how.step2.afterLink")} +
    +
  • +
  • + [3] +
    + {i18n.t("zen.how.step3.title")} - {i18n.t("zen.how.step3.body")} +
    +
  • +
+
+ +
+
+

{i18n.t("zen.privacy.title")}

+
+ [*] +

+ {i18n.t("zen.privacy.beforeExceptions")}{" "} + {i18n.t("zen.privacy.exceptionsLink")}. +

+
+
+
+ +
+ {/*Dax*/} + +
+
+ + Dax Raad + ex-CEO, Terminal Products +
+
+ @OpenCode + {" Zen has been life changing, it's truly a no-brainer."} +
+
+
+ {/*Jay*/} + +
+
+ + Jay V + ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint +
+
+ {"4 out of 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.
+
+
+
+ +
+
+

{i18n.t("common.faq")}

+
+ +
+ + + +
+
+
+ + +
+ ) +} From b1c166edf44faa3cdb2793f24d791e02125eaa50 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 3 Mar 2026 18:30:04 +0000 Subject: [PATCH 02/32] chore(console): add Go to nav --- packages/console/app/src/component/header.tsx | 6 ++++++ packages/console/app/src/i18n/en.ts | 1 + packages/console/app/src/routes/brand/index.css | 4 ++-- packages/console/app/src/routes/changelog/index.css | 4 ++-- packages/console/app/src/routes/download/index.css | 4 ++-- packages/console/app/src/routes/enterprise/index.css | 4 ++-- packages/console/app/src/routes/go/index.css | 4 ++-- packages/console/app/src/routes/index.css | 4 ++-- packages/console/app/src/routes/zen/index.css | 4 ++-- 9 files changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 6ab5ce2f5..5b0a443fb 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -174,6 +174,9 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { +
  • + {i18n.t("nav.go")} +
  • @@ -270,6 +273,9 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • +
  • + {i18n.t("nav.go")} +
  • diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 07a4ddb4c..970ad7c5e 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -6,6 +6,7 @@ export const dict = { "nav.x": "X", "nav.enterprise": "Enterprise", "nav.zen": "Zen", + "nav.go": "Go", "nav.login": "Login", "nav.free": "Free", "nav.home": "Home", diff --git a/packages/console/app/src/routes/brand/index.css b/packages/console/app/src/routes/brand/index.css index 6fe7c9a8d..8a3265159 100644 --- a/packages/console/app/src/routes/brand/index.css +++ b/packages/console/app/src/routes/brand/index.css @@ -86,10 +86,10 @@ display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/changelog/index.css b/packages/console/app/src/routes/changelog/index.css index b441754a6..27b44f062 100644 --- a/packages/console/app/src/routes/changelog/index.css +++ b/packages/console/app/src/routes/changelog/index.css @@ -81,10 +81,10 @@ display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/download/index.css b/packages/console/app/src/routes/download/index.css index 41bb55eee..705302616 100644 --- a/packages/console/app/src/routes/download/index.css +++ b/packages/console/app/src/routes/download/index.css @@ -85,10 +85,10 @@ display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/enterprise/index.css b/packages/console/app/src/routes/enterprise/index.css index d42a817e6..584c94fa5 100644 --- a/packages/console/app/src/routes/enterprise/index.css +++ b/packages/console/app/src/routes/enterprise/index.css @@ -85,10 +85,10 @@ display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 7069f3f21..2167731a9 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -148,10 +148,10 @@ body { display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/index.css b/packages/console/app/src/routes/index.css index 90ea3d696..d06e26595 100644 --- a/packages/console/app/src/routes/index.css +++ b/packages/console/app/src/routes/index.css @@ -212,10 +212,10 @@ body { display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { diff --git a/packages/console/app/src/routes/zen/index.css b/packages/console/app/src/routes/zen/index.css index acdfbe85d..1b5755288 100644 --- a/packages/console/app/src/routes/zen/index.css +++ b/packages/console/app/src/routes/zen/index.css @@ -148,10 +148,10 @@ body { display: flex; justify-content: space-between; align-items: center; - gap: 48px; + gap: 32px; @media (max-width: 55rem) { - gap: 32px; + gap: 24px; } @media (max-width: 48rem) { From c2f5abe7595120843121995df9b6f20d46dbd2f2 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 3 Mar 2026 18:51:53 +0000 Subject: [PATCH 03/32] chore(console): move Enterprise after Go --- packages/console/app/src/component/header.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 5b0a443fb..302337ef2 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -161,9 +161,6 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • -
  • - {i18n.t("nav.enterprise")} -
  • @@ -177,6 +174,9 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.go")}
  • +
  • + {i18n.t("nav.enterprise")} +
  • @@ -260,9 +260,6 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • -
  • - {i18n.t("nav.enterprise")} -
  • @@ -276,6 +273,9 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.go")}
  • +
  • + {i18n.t("nav.enterprise")} +
  • From d80334b2bcea7a5e82cdc71a8fd1cadb54340edf Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 3 Mar 2026 19:01:24 +0000 Subject: [PATCH 04/32] chore(console): update /go hero copy --- packages/console/app/src/routes/go/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 38b44bf79..33793da51 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -49,7 +49,7 @@ export default function Home() {
    -

    {i18n.t("zen.hero.title")}

    +

    Low cost coding models for everyone

    {i18n.t("zen.hero.body")}

    From 12f4315d9d411c8e3d6091876ba41c406d618f01 Mon Sep 17 00:00:00 2001 From: David Hill Date: Tue, 3 Mar 2026 19:04:48 +0000 Subject: [PATCH 05/32] chore(console): trim /go model logos --- packages/console/app/src/routes/go/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 33793da51..1148059b1 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -17,7 +17,7 @@ import { Legal } from "~/component/legal" import { Footer } from "~/component/footer" import { Header } from "~/component/header" import { getLastSeenWorkspaceID } from "../workspace/common" -import { IconGemini, IconMiniMax, IconZai } from "~/component/icon" +import { IconMiniMax, IconZai } from "~/component/icon" import { useI18n } from "~/context/i18n" import { useLanguage } from "~/context/language" import { LocaleLinks } from "~/component/locale-links" @@ -52,6 +52,7 @@ export default function Home() {

    Low cost coding models for everyone

    {i18n.t("zen.hero.body")}

    + {/*
    + */}
    @@ -111,6 +113,7 @@ export default function Home() {
    + {/*
    + */}
    {i18n.t("zen.cta.start")} From a2d3d62db3dcd7bd63d0660d58b4fb0b99b2e603 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 11:26:50 +0000 Subject: [PATCH 06/32] chore(console): move login to end on zen/go --- packages/console/app/src/component/header.tsx | 40 +++++++++---------- packages/console/app/src/routes/go/index.tsx | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 302337ef2..9ec3fe0b8 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -161,22 +161,22 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • -
  • - - - {i18n.t("nav.login")} - - - {i18n.t("nav.zen")} - - -
  • + +
  • + {i18n.t("nav.zen")} +
  • +
  • {i18n.t("nav.go")}
  • {i18n.t("nav.enterprise")}
  • + +
  • + {i18n.t("nav.login")} +
  • +
  • @@ -260,22 +260,22 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) {
  • {i18n.t("nav.docs")}
  • -
  • - - - {i18n.t("nav.login")} - - - {i18n.t("nav.zen")} - - -
  • + +
  • + {i18n.t("nav.zen")} +
  • +
  • {i18n.t("nav.go")}
  • {i18n.t("nav.enterprise")}
  • + +
  • + {i18n.t("nav.login")} +
  • +
  • diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 1148059b1..f991060ba 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -127,7 +127,7 @@ export default function Home() { */} - {i18n.t("zen.cta.start")} + Subscribe to Go - $10/mo Date: Wed, 4 Mar 2026 11:34:44 +0000 Subject: [PATCH 07/32] chore(console): update /go hero body --- packages/console/app/src/routes/go/index.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index f991060ba..e51900293 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -50,7 +50,11 @@ export default function Home() {

    Low cost coding models for everyone

    -

    {i18n.t("zen.hero.body")}

    +

    + Go brings agentic coding to programmers around the world for just $10/month. Generous limits and + reliable access to the most capable open-source models, so you can build with powerful agents without + worrying about cost or availability. +

    {/*
    From 9909f94048cf0b1f325f9867d453534a30b088b0 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 11:46:30 +0000 Subject: [PATCH 08/32] chore(console): hide Go nav item on /go --- packages/console/app/src/component/header.tsx | 22 +++++++++++-------- packages/console/app/src/routes/go/index.tsx | 2 +- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/console/app/src/component/header.tsx b/packages/console/app/src/component/header.tsx index 9ec3fe0b8..24d5a897c 100644 --- a/packages/console/app/src/component/header.tsx +++ b/packages/console/app/src/component/header.tsx @@ -36,7 +36,7 @@ const fetchSvgContent = async (svgPath: string): Promise => { } } -export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { +export function Header(props: { zen?: boolean; go?: boolean; hideGetStarted?: boolean }) { const navigate = useNavigate() const i18n = useI18n() const language = useLanguage() @@ -166,13 +166,15 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { {i18n.t("nav.zen")}
  • -
  • - {i18n.t("nav.go")} -
  • + +
  • + {i18n.t("nav.go")} +
  • +
  • {i18n.t("nav.enterprise")}
  • - +
  • {i18n.t("nav.login")}
  • @@ -265,13 +267,15 @@ export function Header(props: { zen?: boolean; hideGetStarted?: boolean }) { {i18n.t("nav.zen")}
    -
  • - {i18n.t("nav.go")} -
  • + +
  • + {i18n.t("nav.go")} +
  • +
  • {i18n.t("nav.enterprise")}
  • - +
  • {i18n.t("nav.login")}
  • diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index e51900293..2516d2dac 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -42,7 +42,7 @@ export default function Home() {
    -
    +
    From 57095619178036f125d62c0b82d4df2cc2d34ee6 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 12:01:15 +0000 Subject: [PATCH 09/32] chore(console): refine /go hero and pricing copy --- packages/console/app/src/routes/go/index.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 2516d2dac..7b2ad9bdd 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -51,9 +51,9 @@ export default function Home() {

    Low cost coding models for everyone

    - Go brings agentic coding to programmers around the world for just $10/month. Generous limits and - reliable access to the most capable open-source models, so you can build with powerful agents without - worrying about cost or availability. + Go brings agentic coding to programmers around the world. Offering generous limits and reliable access + to the most capable open-source models, so you can build with powerful agents without worrying about + cost or availability.

    {/* @@ -143,9 +143,6 @@ export default function Home() {
    -

    - {i18n.t("zen.pricing.title")} {i18n.t("zen.pricing.fee")} -

    {i18n.t("zen.pricing.body")}

    From e44cdaf887c9f5d819821b7f97370a20c3c5e54b Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 12:15:40 +0000 Subject: [PATCH 10/32] chore(console): use Go ornate logo on /go --- packages/console/app/src/asset/go-ornate-dark.svg | 6 ++++++ packages/console/app/src/asset/go-ornate-light.svg | 6 ++++++ packages/console/app/src/routes/go/index.tsx | 8 ++++---- 3 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 packages/console/app/src/asset/go-ornate-dark.svg create mode 100644 packages/console/app/src/asset/go-ornate-light.svg diff --git a/packages/console/app/src/asset/go-ornate-dark.svg b/packages/console/app/src/asset/go-ornate-dark.svg new file mode 100644 index 000000000..9b617c677 --- /dev/null +++ b/packages/console/app/src/asset/go-ornate-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/app/src/asset/go-ornate-light.svg b/packages/console/app/src/asset/go-ornate-light.svg new file mode 100644 index 000000000..79991973d --- /dev/null +++ b/packages/console/app/src/asset/go-ornate-light.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 7b2ad9bdd..d82f2739a 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -2,8 +2,8 @@ import "./index.css" import { createAsync, query, redirect } from "@solidjs/router" import { Title, Meta } 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 goLogoLight from "../../asset/go-ornate-light.svg" +import goLogoDark from "../../asset/go-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" @@ -47,8 +47,8 @@ export default function Home() {
    - - + +

    Low cost coding models for everyone

    Go brings agentic coding to programmers around the world. Offering generous limits and reliable access From 0a2aa8688d048b07e633065122f73bc0d4ec7e4a Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 12:57:49 +0000 Subject: [PATCH 11/32] chore(console): switch /go page to go.* i18n keys --- packages/console/app/src/i18n/en.ts | 59 ++++++++++++++ packages/console/app/src/routes/go/index.tsx | 81 ++++++++++---------- 2 files changed, 99 insertions(+), 41 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 970ad7c5e..33107fe52 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -244,6 +244,65 @@ export const dict = { "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", "zen.privacy.exceptionsLink": "following exceptions", + "go.title": "OpenCode Go | Low cost coding models for everyone", + "go.hero.title": "Low cost coding models for everyone", + "go.hero.body": + "Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.", + + "go.cta.start": "Subscribe to Go - $10/mo", + "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", + "go.problem.title": "What problem is Go solving?", + "go.problem.body": + "There are so many models available, but only a few work well with coding agents. Most providers configure them differently with varying results.", + "go.problem.subtitle": "We're fixing this for everyone, not just OpenCode users.", + "go.problem.item1": "Testing select models and consulting their teams", + "go.problem.item2": "Working with providers to ensure they're delivered properly", + "go.problem.item3": "Benchmarking all model-provider combinations we recommend", + "go.how.title": "How Go works", + "go.how.body": "Go is a $10/month subscription you can use with OpenCode or any agent.", + "go.how.step1.title": "Create an account", + "go.how.step1.beforeLink": "follow the", + "go.how.step1.link": "setup instructions", + "go.how.step2.title": "Subscribe to Go", + "go.how.step2.link": "$10/month", + "go.how.step2.afterLink": "with generous limits", + "go.how.step3.title": "Start coding", + "go.how.step3.body": "with reliable access to open-source models", + "go.privacy.title": "Your privacy is important to us", + "go.privacy.beforeExceptions": + "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", + "go.privacy.exceptionsLink": "following exceptions", + "go.faq.q1": "What is OpenCode Go?", + "go.faq.a1": + "Go is a low-cost subscription that gives you reliable access to capable open-source models for agentic coding.", + "go.faq.q2": "What models does Go include?", + "go.faq.a2": + "Go focuses on the most capable open-source models available through OpenCode, with generous limits and reliable access.", + "go.faq.q3": "Is Go the same as Zen?", + "go.faq.a3": + "No. Zen is pay-as-you-go, while Go is a $10/month subscription with generous limits and reliable access to open-source models GLM-5, Kimi K2.5, and MiniMax M2.5.", + "go.faq.q4": "How much does Go cost?", + "go.faq.a4.p1.beforePricing": "Go costs", + "go.faq.a4.p1.pricingLink": "$10/month", + "go.faq.a4.p1.afterPricing": "with generous limits.", + "go.faq.a4.p2.beforeAccount": "You can manage your subscription in your", + "go.faq.a4.p2.accountLink": "account", + "go.faq.a4.p3": "Cancel any time.", + "go.faq.q5": "What about data and privacy?", + "go.faq.a5.beforeExceptions": + "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", + "go.faq.a5.exceptionsLink": "following exceptions", + "go.faq.q6": "Can I top up credit?", + "go.faq.a6": "If you need more usage, you can top up credit in your account.", + "go.faq.q7": "Can I cancel?", + "go.faq.a7": "Yes, you can cancel any time.", + "go.faq.q8": "Can I use Go with other coding agents?", + "go.faq.a8": "Yes, you can use Go with any agent. Follow the setup instructions in your preferred coding agent.", + + "go.faq.q9": "What is the difference between the free models included and Go?", + "go.faq.a9": + "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5, Kimi K2.5, and MiniMax M2.5 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", + "zen.api.error.rateLimitExceeded": "Rate limit exceeded. Please try again later.", "zen.api.error.modelNotSupported": "Model {{model}} not supported", "zen.api.error.modelFormatNotSupported": "Model {{model}} not supported for format {{format}}", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index d82f2739a..abcd2a94a 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -35,7 +35,7 @@ export default function Home() { return (

    {/**/} - {i18n.t("zen.title")} + {i18n.t("go.title")} @@ -49,12 +49,8 @@ export default function Home() {
    -

    Low cost coding models for everyone

    -

    - Go brings agentic coding to programmers around the world. Offering generous limits and reliable access - to the most capable open-source models, so you can build with powerful agents without worrying about - cost or availability. -

    +

    {i18n.t("go.hero.title")}

    +

    {i18n.t("go.hero.body")}

    {/*
    @@ -131,7 +127,7 @@ export default function Home() { */}
    - Subscribe to Go - $10/mo + {i18n.t("go.cta.start")}
    -

    {i18n.t("zen.pricing.body")}

    +

    {i18n.t("go.pricing.body")}

    @@ -155,50 +151,50 @@ export default function Home() {
    -

    {i18n.t("zen.problem.title")}

    -

    {i18n.t("zen.problem.body")}

    +

    {i18n.t("go.problem.title")}

    +

    {i18n.t("go.problem.body")}

    -

    {i18n.t("zen.problem.subtitle")}

    +

    {i18n.t("go.problem.subtitle")}

    • - [*] {i18n.t("zen.problem.item1")} + [*] {i18n.t("go.problem.item1")}
    • - [*] {i18n.t("zen.problem.item2")} + [*] {i18n.t("go.problem.item2")}
    • - [*] {i18n.t("zen.problem.item3")} + [*] {i18n.t("go.problem.item3")}
    -

    {i18n.t("zen.how.title")}

    -

    {i18n.t("zen.how.body")}

    +

    {i18n.t("go.how.title")}

    +

    {i18n.t("go.how.body")}

    @@ -206,12 +202,12 @@ export default function Home() {
    -

    {i18n.t("zen.privacy.title")}

    +

    {i18n.t("go.privacy.title")}

    [*]

    - {i18n.t("zen.privacy.beforeExceptions")}{" "} - {i18n.t("zen.privacy.exceptionsLink")}. + {i18n.t("go.privacy.beforeExceptions")}{" "} + {i18n.t("go.privacy.exceptionsLink")}.

    @@ -296,36 +292,39 @@ export default function Home() {
    From eb718567334d9118497772d20099f6ef90ec318f Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 13:05:19 +0000 Subject: [PATCH 12/32] docs: send Go landing page links to Go docs --- packages/console/app/src/routes/go/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index abcd2a94a..74da24832 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -178,7 +178,7 @@ export default function Home() { [1]
    {i18n.t("go.how.step1.title")} - {i18n.t("go.how.step1.beforeLink")}{" "} - + {i18n.t("go.how.step1.link")}
    @@ -187,7 +187,7 @@ export default function Home() { [2]
    {i18n.t("go.how.step2.title")} -{" "} - {i18n.t("go.how.step2.link")}{" "} + {i18n.t("go.how.step2.link")}{" "} {i18n.t("go.how.step2.afterLink")}
    From dd4ad5f2c51be97c1de6526245bab999caaf77f9 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 13:08:21 +0000 Subject: [PATCH 13/32] chore(console): edit copy --- packages/console/app/src/i18n/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 33107fe52..7c5f1ccc5 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -299,7 +299,7 @@ export const dict = { "go.faq.q8": "Can I use Go with other coding agents?", "go.faq.a8": "Yes, you can use Go with any agent. Follow the setup instructions in your preferred coding agent.", - "go.faq.q9": "What is the difference between the free models included and Go?", + "go.faq.q9": "What is the difference between free models and Go?", "go.faq.a9": "Free models include Big Pickle plus promotional models available at the time, with a quota of 200 requests/day. Go includes GLM-5, Kimi K2.5, and MiniMax M2.5 with higher request quotas enforced across rolling windows (5-hour, weekly, and monthly), roughly equivalent to $12 per 5 hours, $30 per week, and $60 per month (actual request counts vary by model and usage).", From ad563381087084de2cd7b88ad25965b52ed162da Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 13:24:08 +0000 Subject: [PATCH 14/32] chore(console): update copy --- packages/console/app/src/i18n/en.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 7c5f1ccc5..41c3a76fc 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -253,11 +253,12 @@ export const dict = { "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", "go.problem.title": "What problem is Go solving?", "go.problem.body": - "There are so many models available, but only a few work well with coding agents. Most providers configure them differently with varying results.", - "go.problem.subtitle": "We're fixing this for everyone, not just OpenCode users.", - "go.problem.item1": "Testing select models and consulting their teams", - "go.problem.item2": "Working with providers to ensure they're delivered properly", - "go.problem.item3": "Benchmarking all model-provider combinations we recommend", + "We're focused on bringing the OpenCode experience to as many people as possible. OpenCode Go is a low cost ($10/month) subscription designed to bring agentic coding to programmers around the world. It provides generous limits and reliable access to the most capable open source models.", + "go.problem.subtitle": + " ", + "go.problem.item1": "Low cost subscription pricing", + "go.problem.item2": "Generous limits and reliable access", + "go.problem.item3": "Built for as many programmers as possible", "go.how.title": "How Go works", "go.how.body": "Go is a $10/month subscription you can use with OpenCode or any agent.", "go.how.step1.title": "Create an account", From 7c215c0d02796803cd20602bb4b04a7d3c43760a Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 15:21:07 +0000 Subject: [PATCH 15/32] docs: replace Go landing page video with interactive limits graph Users can now see a clear visual comparison of request limits between Free tier and Go tier across all available models, making it easier to understand the value of a Go subscription at a glance. --- packages/console/app/src/i18n/en.ts | 5 +- packages/console/app/src/routes/go/index.css | 313 ++++++++++++++++++- packages/console/app/src/routes/go/index.tsx | 141 ++++++++- 3 files changed, 446 insertions(+), 13 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 41c3a76fc..5052529c8 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -251,11 +251,12 @@ export const dict = { "go.cta.start": "Subscribe to Go - $10/mo", "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", + "go.graph.free": "Free", + "go.graph.go": "Go", "go.problem.title": "What problem is Go solving?", "go.problem.body": "We're focused on bringing the OpenCode experience to as many people as possible. OpenCode Go is a low cost ($10/month) subscription designed to bring agentic coding to programmers around the world. It provides generous limits and reliable access to the most capable open source models.", - "go.problem.subtitle": - " ", + "go.problem.subtitle": " ", "go.problem.item1": "Low cost subscription pricing", "go.problem.item2": "Generous limits and reliable access", "go.problem.item3": "Built for as many programmers as possible", diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 2167731a9..e0a1ead0c 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -8,6 +8,19 @@ } } +@keyframes go-graph-line { + to { + stroke-dashoffset: 0; + } +} + +@keyframes go-graph-point { + to { + opacity: 1; + transform: scale(1); + } +} + [data-page="go"] { --color-background: hsl(0, 20%, 99%); --color-background-weak: hsl(0, 8%, 97%); @@ -16,6 +29,10 @@ --color-background-interactive: hsl(62, 84%, 88%); --color-background-interactive-weaker: hsl(64, 74%, 95%); + --color-go-1: hsl(61.9, 82.6%, 77.5%); + --color-go-2: hsl(62.4, 78.6%, 56.1%); + --color-go-3: hsl(62.1, 100%, 39.8%); + --color-text: hsl(0, 1%, 39%); --color-text-weak: hsl(0, 1%, 74%); --color-text-weaker: hsl(30, 2%, 81%); @@ -37,6 +54,10 @@ --color-background-interactive: hsl(62, 100%, 90%); --color-background-interactive-weaker: hsl(60, 20%, 8%); + --color-go-1: hsl(62.1, 64.9%, 25.7%); + --color-go-2: hsl(61.7, 46.4%, 53.9%); + --color-go-3: hsl(61.9, 100%, 50%); + --color-text: hsl(0, 4%, 71%); --color-text-weak: hsl(0, 2%, 49%); --color-text-weaker: hsl(0, 3%, 28%); @@ -381,12 +402,292 @@ body { [data-component="comparison"] { border-top: 1px solid var(--color-border-weak); - video { - width: 100%; - height: auto; - max-width: none; - max-height: none; - display: block; + padding: 0; + background: + radial-gradient(1200px 400px at 15% 0%, rgba(0, 0, 0, 0.035), transparent 55%), + radial-gradient(900px 320px at 85% 15%, rgba(0, 0, 0, 0.02), transparent 60%), var(--color-background-weak); + + @media (prefers-color-scheme: dark) { + background: + radial-gradient(1200px 400px at 15% 0%, rgba(255, 255, 255, 0.03), transparent 55%), + radial-gradient(900px 320px at 85% 15%, rgba(255, 255, 255, 0.02), transparent 60%), + var(--color-background-weak); + } + + [data-component="limit-graph"] { + margin: 0 auto; + max-width: calc(100% - (var(--padding) * 2)); + border: none; + background: transparent; + padding: 18px 18px 56px; + + [data-slot="plot"] { + position: relative; + } + + [data-slot="plot-labels"] { + position: absolute; + inset: 0; + pointer-events: none; + } + + [data-row-label] { + position: absolute; + left: 0; + top: var(--y); + transform: translateY(-50%); + color: var(--color-text-strong); + font-size: 16px; + font-weight: 700; + } + + svg { + width: 100%; + height: auto; + aspect-ratio: 720 / 220; + display: block; + } + + [data-grid] { + stroke: var(--color-border); + stroke-width: 1; + opacity: 0.6; + } + + [data-tick] { + fill: var(--color-text-weak); + font-size: 12px; + } + + [data-row] { + fill: var(--color-text-strong); + font-size: 13px; + font-weight: 600; + } + + [data-stub] { + stroke: var(--color-border); + stroke-width: 2; + stroke-linecap: round; + opacity: 0.55; + } + + [data-range] { + stroke: var(--color-text-strong); + stroke-width: 2; + stroke-linecap: round; + opacity: 0.65; + } + + [data-point] { + vector-effect: non-scaling-stroke; + stroke-width: 1; + transform-box: fill-box; + transform-origin: center; + } + + [data-point][data-kind="free"] { + fill: var(--color-background); + stroke: var(--color-text-strong); + } + + [data-point][data-kind="go"] { + fill: var(--color-background-interactive); + stroke: var(--color-text-strong); + } + + [data-point][data-kind="go"][data-model="glm"] { + fill: var(--color-go-1); + } + + [data-point][data-kind="go"][data-model="kimi"] { + fill: var(--color-go-2); + } + + [data-point][data-kind="go"][data-model="minimax"] { + fill: var(--color-go-3); + } + + [data-animate="line"] { + stroke-dasharray: 900; + stroke-dashoffset: 900; + } + + &[data-visible] [data-animate="line"] { + animation: go-graph-line 1000ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards; + animation-delay: 80ms; + } + + [data-point] { + opacity: 0; + transform: scale(0.85); + } + + &[data-visible] [data-point] { + animation: go-graph-point 520ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards; + animation-delay: var(--d, 0ms); + } + + @media (prefers-reduced-motion: reduce) { + [data-animate="line"] { + stroke-dashoffset: 0; + animation: none; + } + [data-point] { + opacity: 1; + transform: none; + animation: none; + } + } + + figcaption { + margin-top: 34px; + display: flex; + flex-direction: column; + gap: 10px; + font-size: 13px; + } + + [data-slot="caption-row"] { + display: flex; + width: 100%; + } + + [data-slot="caption-left"] { + display: grid; + width: 100%; + grid-template-columns: var(--start, 16.9%) minmax(0, 1fr); + grid-template-rows: auto auto; + align-items: center; + column-gap: 0; + row-gap: 0; + min-width: 0; + } + + [data-slot="caption-meta"] { + display: contents; + } + + [data-slot="caption-label"] { + color: var(--color-text-strong); + font-weight: 650; + white-space: nowrap; + line-height: 1; + grid-column: 1; + grid-row: 1; + } + + [data-slot="caption-link"] { + color: var(--color-text-strong); + text-decoration-thickness: 1px; + width: fit-content; + line-height: 1; + grid-column: 1; + grid-row: 2; + align-self: start; + } + + [data-slot="legend"] { + display: flex; + width: 100%; + flex-wrap: nowrap; + gap: 10px; + min-width: 0; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + padding-bottom: 8px; + margin-left: -12px; + grid-column: 2; + grid-row: 1; + align-self: center; + + [data-item] { + display: inline-flex; + flex: 0 0 auto; + align-items: center; + gap: 8px; + border: 1px solid var(--color-border-weak); + background: var(--color-background); + padding: 6px 10px; + border-radius: 999px; + max-width: 100%; + } + + [data-dot] { + width: 10px; + height: 10px; + border-radius: 999px; + display: inline-block; + border: 1px solid var(--color-text-strong); + background: var(--color-background); + flex: 0 0 auto; + } + + [data-dot][data-kind="go"] { + background: var(--color-background-interactive); + } + + [data-dot][data-kind="go"][data-model="glm"] { + background: var(--color-go-1); + } + + [data-dot][data-kind="go"][data-model="kimi"] { + background: var(--color-go-2); + } + + [data-dot][data-kind="go"][data-model="minimax"] { + background: var(--color-go-3); + } + + [data-name] { + color: var(--color-text); + white-space: nowrap; + } + + [data-value] { + color: var(--color-text-strong); + font-weight: 600; + white-space: nowrap; + } + } + + [data-slot="caption-note"] { + color: var(--color-text-weak); + font-size: 12px; + } + + @media (max-width: 56.25rem) { + [data-slot="caption-left"] { + grid-template-columns: var(--start, 16.9%) minmax(0, 1fr); + grid-template-rows: auto auto; + align-items: start; + } + + [data-slot="legend"] { + grid-column: 2; + grid-row: 1; + } + + [data-slot="caption-meta"] { + display: flex; + gap: 24px; + align-items: baseline; + grid-column: 2; + grid-row: 2; + margin-top: 12px; + } + + [data-slot="caption-label"] { + grid-column: auto; + grid-row: auto; + } + + [data-slot="caption-link"] { + grid-column: auto; + grid-row: auto; + align-self: baseline; + } + } } } diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 74da24832..af77917a3 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -1,11 +1,10 @@ import "./index.css" import { createAsync, query, redirect } from "@solidjs/router" import { Title, Meta } from "@solidjs/meta" +import { For, createSignal, onCleanup, onMount } from "solid-js" //import { HttpHeader } from "@solidjs/start" import goLogoLight from "../../asset/go-ornate-light.svg" import goLogoDark from "../../asset/go-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" @@ -28,6 +27,137 @@ const checkLoggedIn = query(async () => { if (workspaceID) throw redirect(`/workspace/${workspaceID}`) }, "checkLoggedIn.get") +function LimitsGraph(props: { href: string; labels: { free: string; go: string } }) { + let root!: HTMLElement + const [visible, setVisible] = createSignal(false) + + onMount(() => { + if (typeof IntersectionObserver === "undefined") return setVisible(true) + const observer = new IntersectionObserver( + (entries) => { + const entry = entries[0] + if (!entry?.isIntersecting) return + setVisible(true) + observer.disconnect() + }, + { threshold: 0.35 }, + ) + observer.observe(root) + onCleanup(() => observer.disconnect()) + }) + + const free = 200 * 30 + const models = [ + { id: "glm", name: "GLM-5", month: 5750, d: "120ms" }, + { id: "kimi", name: "Kimi K2.5", month: 9250, d: "240ms" }, + { id: "minimax", name: "MiniMax M2.5", month: 100000, d: "360ms" }, + ] + const scale = 18 + const ratio = (n: number) => n / free + + const w = 720 + const h = 220 + const left = 88 + const right = 24 + const top = 22 + const bottom = 46 + const plot = w - left - right + const x = (r: number) => left + (Math.min(r, scale) / scale) * plot + const start = (x(1) / w) * 100 + + const yFree = 74 + const yGo = 134 + const ticks = [1, 2, 5, 10, 15] + const y = (n: number) => `${(n / h) * 100}%` + + return ( +
    +
    + + +
    + + {props.labels.free} + + + {props.labels.go} + +
    +
    + +
    +
    +
    +
    + Requests/month + + Usage limits + +
    +
    + + + Free + {free.toLocaleString()} + + + {(m) => ( + + + {m.name} + {m.month.toLocaleString()} + + )} + +
    +
    +
    +
    +
    + ) +} + export default function Home() { const loggedin = createAsync(() => checkLoggedIn()) const i18n = useI18n() @@ -144,9 +274,10 @@ export default function Home() {
    - +
    From 61795d794e980f1faa257c4d1e1521286012bc85 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 15:24:51 +0000 Subject: [PATCH 16/32] docs: clarify Go models in FAQ answer --- packages/console/app/src/i18n/en.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 5052529c8..41bb43890 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -278,8 +278,7 @@ export const dict = { "go.faq.a1": "Go is a low-cost subscription that gives you reliable access to capable open-source models for agentic coding.", "go.faq.q2": "What models does Go include?", - "go.faq.a2": - "Go focuses on the most capable open-source models available through OpenCode, with generous limits and reliable access.", + "go.faq.a2": "Go includes GLM-5, Kimi K2.5, and MiniMax M2.5, with generous limits and reliable access.", "go.faq.q3": "Is Go the same as Zen?", "go.faq.a3": "No. Zen is pay-as-you-go, while Go is a $10/month subscription with generous limits and reliable access to open-source models GLM-5, Kimi K2.5, and MiniMax M2.5.", From d94c516402445d39b05a2924ae4dbcf71dedb259 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 15:47:53 +0000 Subject: [PATCH 17/32] docs: update Go privacy copy for global hosting --- packages/console/app/src/i18n/en.ts | 7 +++++++ packages/console/app/src/routes/go/index.tsx | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 41bb43890..de0e4e652 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -55,6 +55,7 @@ export const dict = { "common.cancel": "Cancel", "common.creating": "Creating...", "common.create": "Create", + "common.contactUs": "Contact us", "common.videoUnsupported": "Your browser does not support the video tag.", "common.figure": "Fig {{n}}.", @@ -271,6 +272,9 @@ export const dict = { "go.how.step3.title": "Start coding", "go.how.step3.body": "with reliable access to open-source models", "go.privacy.title": "Your privacy is important to us", + "go.privacy.body": + "The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.", + "go.privacy.contactAfter": "if you have any questions.", "go.privacy.beforeExceptions": "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", "go.privacy.exceptionsLink": "following exceptions", @@ -290,6 +294,9 @@ export const dict = { "go.faq.a4.p2.accountLink": "account", "go.faq.a4.p3": "Cancel any time.", "go.faq.q5": "What about data and privacy?", + "go.faq.a5.body": + "The plan is designed primarily for international users, with models hosted in the US, EU, and Singapore for stable global access.", + "go.faq.a5.contactAfter": "if you have any questions.", "go.faq.a5.beforeExceptions": "Go models are hosted in the US. Providers follow a zero-retention policy and do not use your data for model training, with the", "go.faq.a5.exceptionsLink": "following exceptions", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index af77917a3..c308eaba2 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -337,8 +337,8 @@ export default function Home() {
    [*]

    - {i18n.t("go.privacy.beforeExceptions")}{" "} - {i18n.t("go.privacy.exceptionsLink")}. + {i18n.t("go.privacy.body")} {i18n.t("common.contactUs")}{" "} + {i18n.t("go.privacy.contactAfter")}

    @@ -437,15 +437,15 @@ export default function Home() {
  • {i18n.t("go.faq.a4.p1.beforePricing")}{" "} - {i18n.t("go.faq.a4.p1.pricingLink")}{" "} + {i18n.t("go.faq.a4.p1.pricingLink")}{" "} {i18n.t("go.faq.a4.p1.afterPricing")} {i18n.t("go.faq.a4.p2.beforeAccount")}{" "} {i18n.t("go.faq.a4.p2.accountLink")}. {i18n.t("go.faq.a4.p3")}
  • - {i18n.t("go.faq.a5.beforeExceptions")}{" "} - {i18n.t("go.faq.a5.exceptionsLink")}. + {i18n.t("go.faq.a5.body")} {i18n.t("common.contactUs")}{" "} + {i18n.t("go.faq.a5.contactAfter")}
  • From c6187ee40f345b55fc3cacf9ff071cc35352e6de Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 15:49:45 +0000 Subject: [PATCH 18/32] =?UTF-8?q?docs:=20de-link=20Go=20testimonials=20and?= =?UTF-8?q?=20swap=20Zen=E2=86=92Go?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/console/app/src/routes/go/index.css | 4 - packages/console/app/src/routes/go/index.tsx | 106 ++++++++----------- 2 files changed, 46 insertions(+), 64 deletions(-) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index e0a1ead0c..2b5ddc970 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -972,10 +972,6 @@ body { flex-direction: column; gap: 20px; - a { - text-decoration: none; - } - [data-slot="testimonial"] { background: var(--color-background-weak); border-radius: 6px; diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index c308eaba2..ca445e04a 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -346,75 +346,61 @@ export default function Home() {
    {/*Dax*/} - -
    -
    - - Dax Raad - ex-CEO, Terminal Products -
    -
    - @OpenCode - {" Zen has been life changing, it's truly a no-brainer."} -
    +
    +
    + + Dax Raad + ex-CEO, Terminal Products
    -
    +
    + @OpenCode Zen Go has been life changing, it's truly a no-brainer. +
    +
    {/*Jay*/} - -
    -
    - - Jay V - ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint -
    -
    - {"4 out of 5 people on our team love using "} - @OpenCode - {" Zen."} -
    +
    +
    + + Jay V + ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint
    -
    +
    + {"4 out of 5 people on our team love using "} + @OpenCode Zen Go. +
    +
    {/*Adam*/} - -
    From ca5a7378deb77ad35a70d7182f750a544a2b7426 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 15:58:58 +0000 Subject: [PATCH 19/32] docs: localize Go graph and testimonial copy --- packages/console/app/src/i18n/en.ts | 26 ++++++++ packages/console/app/src/routes/go/index.tsx | 63 ++++++++++---------- 2 files changed, 59 insertions(+), 30 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index de0e4e652..065a02be3 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -254,6 +254,32 @@ export const dict = { "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", "go.graph.free": "Free", "go.graph.go": "Go", + "go.graph.label": "Requests/month", + "go.graph.usageLimits": "Usage limits", + "go.graph.tick": "{{n}}x", + "go.graph.aria": "Requests per month: {{free}} vs {{go}}", + + "go.testimonials.brand.zen": "Zen", + "go.testimonials.brand.go": "Go", + "go.testimonials.handle": "@OpenCode", + "go.testimonials.dax.name": "Dax Raad", + "go.testimonials.dax.title": "ex-CEO, Terminal Products", + "go.testimonials.dax.quoteAfter": "has been life changing, it's truly a no-brainer.", + "go.testimonials.jay.name": "Jay V", + "go.testimonials.jay.title": "ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint", + "go.testimonials.jay.quoteBefore": "4 out of 5 people on our team love using", + "go.testimonials.jay.quoteAfter": ".", + "go.testimonials.adam.name": "Adam Elmore", + "go.testimonials.adam.title": "ex-Hero, AWS", + "go.testimonials.adam.quoteBefore": "I can't recommend", + "go.testimonials.adam.quoteAfter": "enough. Seriously, it's really good.", + "go.testimonials.david.name": "David Hill", + "go.testimonials.david.title": "ex-Head of Design, Laravel", + "go.testimonials.david.quoteBefore": "With", + "go.testimonials.david.quoteAfter": "I know all the models are tested and perfect for coding agents.", + "go.testimonials.frank.name": "Frank Wang", + "go.testimonials.frank.title": "ex-Intern, Nvidia (4 times)", + "go.testimonials.frank.quote": "I wish I was still at Nvidia.", "go.problem.title": "What problem is Go solving?", "go.problem.body": "We're focused on bringing the OpenCode experience to as many people as possible. OpenCode Go is a low cost ($10/month) subscription designed to bring agentic coding to programmers around the world. It provides generous limits and reliable access to the most capable open source models.", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index ca445e04a..ac2f10a99 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -27,10 +27,12 @@ const checkLoggedIn = query(async () => { if (workspaceID) throw redirect(`/workspace/${workspaceID}`) }, "checkLoggedIn.get") -function LimitsGraph(props: { href: string; labels: { free: string; go: string } }) { +function LimitsGraph(props: { href: string }) { let root!: HTMLElement const [visible, setVisible] = createSignal(false) + const i18n = useI18n() + onMount(() => { if (typeof IntersectionObserver === "undefined") return setVisible(true) const observer = new IntersectionObserver( @@ -73,7 +75,7 @@ function LimitsGraph(props: { href: string; labels: { free: string; go: string } return (
    - {t}x + {i18n.t("go.graph.tick", { n: t })} )} @@ -118,10 +120,10 @@ function LimitsGraph(props: { href: string; labels: { free: string; go: string }
    - {props.labels.free} + {i18n.t("go.graph.free")} - {props.labels.go} + {i18n.t("go.graph.go")}
  • @@ -130,15 +132,15 @@ function LimitsGraph(props: { href: string; labels: { free: string; go: string }
    - Requests/month + {i18n.t("go.graph.label")} - Usage limits + {i18n.t("go.graph.usageLimits")}
    - Free + {i18n.t("go.graph.free")} {free.toLocaleString()} @@ -274,10 +276,7 @@ export default function Home() {
    - +
    @@ -349,57 +348,61 @@ export default function Home() {
    - Dax Raad - ex-CEO, Terminal Products + {i18n.t("go.testimonials.dax.name")} + {i18n.t("go.testimonials.dax.title")}
    - @OpenCode Zen Go has been life changing, it's truly a no-brainer. + {i18n.t("go.testimonials.handle")} {i18n.t("go.testimonials.brand.zen")}{" "} + {i18n.t("go.testimonials.brand.go")} {i18n.t("go.testimonials.dax.quoteAfter")}
    {/*Jay*/}
    - Jay V - ex-Founder, SEED, PM, Melt, Pop, Dapt, Cadmus, and ViewPoint + {i18n.t("go.testimonials.jay.name")} + {i18n.t("go.testimonials.jay.title")}
    - {"4 out of 5 people on our team love using "} - @OpenCode Zen Go. + {i18n.t("go.testimonials.jay.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} + {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")} + {i18n.t("go.testimonials.jay.quoteAfter")}
    {/*Adam*/}
    - Adam Elmore - ex-Hero, AWS + {i18n.t("go.testimonials.adam.name")} + {i18n.t("go.testimonials.adam.title")}
    - {"I can't recommend "} - @OpenCode Zen Go enough. Seriously, it's really good. + {i18n.t("go.testimonials.adam.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} + {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")}{" "} + {i18n.t("go.testimonials.adam.quoteAfter")}
    {/*David*/}
    - David Hill - ex-Head of Design, Laravel + {i18n.t("go.testimonials.david.name")} + {i18n.t("go.testimonials.david.title")}
    - {"With "} - @OpenCode Zen Go I know all the models are tested and perfect for coding agents. + {i18n.t("go.testimonials.david.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} + {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")}{" "} + {i18n.t("go.testimonials.david.quoteAfter")}
    {/*Frank*/}
    - Frank Wang - ex-Intern, Nvidia (4 times) + {i18n.t("go.testimonials.frank.name")} + {i18n.t("go.testimonials.frank.title")}
    -
    I wish I was still at Nvidia.
    +
    {i18n.t("go.testimonials.frank.quote")}
    From b42a63b882dbde071b62836b5234a5b197e5b317 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:02:37 +0000 Subject: [PATCH 20/32] docs: make Go hero CTA translatable with pricing emphasis --- packages/console/app/src/i18n/en.ts | 5 ++++- packages/console/app/src/routes/go/index.css | 8 ++++++++ packages/console/app/src/routes/go/index.tsx | 15 ++++++++++++++- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 065a02be3..9cd896fe2 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -250,7 +250,10 @@ export const dict = { "go.hero.body": "Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.", - "go.cta.start": "Subscribe to Go - $10/mo", + "go.cta.start": "Subscribe to Go", + "go.cta.template": "{{text}} {{price}}", + "go.cta.text": "Subscribe to Go", + "go.cta.price": "$10/month", "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", "go.graph.free": "Free", "go.graph.go": "Go", diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 2b5ddc970..5a66de678 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -359,6 +359,14 @@ body { width: fit-content; gap: 12px; text-decoration: none; + + [data-slot="cta-price"] { + opacity: 0.6; + } + + svg { + opacity: 0.6; + } } a:hover { diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index ac2f10a99..83dfc31ee 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -259,7 +259,20 @@ export default function Home() { */}
    - {i18n.t("go.cta.start")} + + + {(part) => { + if (part === "{{text}}") return {i18n.t("go.cta.text")} + if (part === "{{price}}") return {i18n.t("go.cta.price")} + return part + }} + + Date: Wed, 4 Mar 2026 16:09:51 +0000 Subject: [PATCH 21/32] tui: reduce excessive spacing in go route layout to improve visual balance --- packages/console/app/src/routes/go/index.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 5a66de678..c3d344c4b 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -354,7 +354,7 @@ body { border-radius: 4px; font-weight: 500; cursor: pointer; - margin-bottom: 56px; + margin-bottom: 40px; display: flex; width: fit-content; gap: 12px; @@ -396,7 +396,7 @@ body { } p:first-child { - margin-bottom: 24px; + margin-bottom: 0; color: var(--color-text); display: flex; gap: 8px; From 744c38cc7cfd4741227b9a1951ccba57668e2184 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:18:11 +0000 Subject: [PATCH 22/32] tui: clarify which models are available in Go subscription Adds list of included AI models (GLM-5, Kimi K2.5, and MiniMax M2.5) to the Go page so users know exactly what model access their subscription provides --- packages/console/app/src/i18n/en.ts | 1 + packages/console/app/src/routes/go/index.tsx | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 9cd896fe2..01e5742dd 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -290,6 +290,7 @@ export const dict = { "go.problem.item1": "Low cost subscription pricing", "go.problem.item2": "Generous limits and reliable access", "go.problem.item3": "Built for as many programmers as possible", + "go.problem.item4": "Includes GLM-5, Kimi K2.5, and MiniMax M2.5", "go.how.title": "How Go works", "go.how.body": "Go is a $10/month subscription you can use with OpenCode or any agent.", "go.how.step1.title": "Create an account", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 83dfc31ee..3c1033074 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -308,6 +308,9 @@ export default function Home() {
  • [*] {i18n.t("go.problem.item3")}
  • +
  • + [*] {i18n.t("go.problem.item4")} +
  • From 0f1f55a24c18e4460872db96aad5bbb08b0fe5f7 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:35:03 +0000 Subject: [PATCH 23/32] tui: show Go request limits per 5-hour session --- packages/console/app/src/i18n/en.ts | 4 ++-- packages/console/app/src/routes/go/index.tsx | 24 +++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 01e5742dd..3f39fcd9d 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -257,10 +257,10 @@ export const dict = { "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", "go.graph.free": "Free", "go.graph.go": "Go", - "go.graph.label": "Requests/month", + "go.graph.label": "Requests/5h", "go.graph.usageLimits": "Usage limits", "go.graph.tick": "{{n}}x", - "go.graph.aria": "Requests per month: {{free}} vs {{go}}", + "go.graph.aria": "Requests per 5h: {{free}} vs {{go}}", "go.testimonials.brand.zen": "Zen", "go.testimonials.brand.go": "Go", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 3c1033074..4f737b4ee 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -48,13 +48,12 @@ function LimitsGraph(props: { href: string }) { onCleanup(() => observer.disconnect()) }) - const free = 200 * 30 + const free = 200 const models = [ - { id: "glm", name: "GLM-5", month: 5750, d: "120ms" }, - { id: "kimi", name: "Kimi K2.5", month: 9250, d: "240ms" }, - { id: "minimax", name: "MiniMax M2.5", month: 100000, d: "360ms" }, + { id: "glm", name: "GLM-5", req: 1150, d: "120ms" }, + { id: "kimi", name: "Kimi K2.5", req: 1850, d: "240ms" }, + { id: "minimax", name: "MiniMax M2.5", req: 20000, d: "360ms" }, ] - const scale = 18 const ratio = (n: number) => n / free const w = 720 @@ -64,12 +63,14 @@ function LimitsGraph(props: { href: string }) { const top = 22 const bottom = 46 const plot = w - left - right - const x = (r: number) => left + (Math.min(r, scale) / scale) * plot + const rmax = Math.max(1, ...models.map((m) => ratio(m.req))) + const log = (n: number) => Math.log10(Math.max(n, 1)) + const x = (r: number) => left + (log(r) / log(rmax)) * plot const start = (x(1) / w) * 100 const yFree = 74 const yGo = 134 - const ticks = [1, 2, 5, 10, 15] + const ticks = [1, 2, 5, 10, 25, 50, 100].filter((t) => t <= rmax) const y = (n: number) => `${(n / h) * 100}%` return ( @@ -100,10 +101,11 @@ function LimitsGraph(props: { href: string }) { + {(m) => ( - + )} @@ -148,7 +150,7 @@ function LimitsGraph(props: { href: string }) { {m.name} - {m.month.toLocaleString()} + {m.req.toLocaleString()} )} From de6a6af5ab6986d05971728848f1ac802ad75f34 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:42:30 +0000 Subject: [PATCH 24/32] tweak(ui): remove section --- packages/console/app/src/routes/go/index.css | 37 -------------------- packages/console/app/src/routes/go/index.tsx | 13 ------- 2 files changed, 50 deletions(-) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index c3d344c4b..812a91c2f 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -769,43 +769,6 @@ body { } } - [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: 700; - color: var(--color-text); - margin-bottom: 12px; - } - - div { - display: flex; - gap: 12px; - } - - p { - } - - span { - color: var(--color-icon); - line-height: 200%; - - @media (max-width: 60rem) { - line-height: 180%; - } - } - - div { - display: flex; - gap: 12px; - } - } - } - [data-component="email"] { border-top: 1px solid var(--color-border-weak); padding: var(--vertical-padding) var(--padding); diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 4f737b4ee..b43f9a710 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -348,19 +348,6 @@ export default function Home() { -
    - -
    -
    {/*Dax*/}
    From b7198c28c8cfd9fb01aaf9a6b9bd25619b0ea111 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:43:43 +0000 Subject: [PATCH 25/32] tweak(ui): darker text --- packages/console/app/src/routes/go/index.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 812a91c2f..dee9011e1 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -467,6 +467,12 @@ body { font-size: 12px; } + @media (prefers-color-scheme: light) { + [data-tick] { + fill: color-mix(in srgb, var(--color-text-weak) 82%, var(--color-text-strong)); + } + } + [data-row] { fill: var(--color-text-strong); font-size: 13px; From 6f232717417853df38bbd3b3241354bd2aa08e22 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:45:34 +0000 Subject: [PATCH 26/32] chore(ui): remove quotes --- packages/console/app/src/routes/go/index.css | 91 -------------------- packages/console/app/src/routes/go/index.tsx | 68 --------------- 2 files changed, 159 deletions(-) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index dee9011e1..34be47f0d 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -942,97 +942,6 @@ body { } } - [data-component="testimonials"] { - border-top: 1px solid var(--color-border-weak); - padding: var(--vertical-padding) var(--padding); - display: flex; - flex-direction: column; - gap: 20px; - - [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: 30rem) { - flex-direction: column-reverse; - gap: 24px; - } - - [data-slot="name"] { - display: flex; - gap: 16px; - - strong { - font-weight: 500; - flex: 0 0 auto; - } - - span { - color: var(--color-text); - } - - @media (max-width: 30rem) { - 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: 30rem) { - 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; diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index b43f9a710..9e4f0eefd 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -5,11 +5,6 @@ import { For, createSignal, onCleanup, onMount } from "solid-js" //import { HttpHeader } from "@solidjs/start" import goLogoLight from "../../asset/go-ornate-light.svg" import goLogoDark from "../../asset/go-ornate-dark.svg" -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 { EmailSignup } from "~/component/email-signup" import { Faq } from "~/component/faq" import { Legal } from "~/component/legal" @@ -348,69 +343,6 @@ export default function Home() {
    -
    - {/*Dax*/} -
    -
    - - {i18n.t("go.testimonials.dax.name")} - {i18n.t("go.testimonials.dax.title")} -
    -
    - {i18n.t("go.testimonials.handle")} {i18n.t("go.testimonials.brand.zen")}{" "} - {i18n.t("go.testimonials.brand.go")} {i18n.t("go.testimonials.dax.quoteAfter")} -
    -
    - {/*Jay*/} -
    -
    - - {i18n.t("go.testimonials.jay.name")} - {i18n.t("go.testimonials.jay.title")} -
    -
    - {i18n.t("go.testimonials.jay.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} - {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")} - {i18n.t("go.testimonials.jay.quoteAfter")} -
    -
    - {/*Adam*/} -
    -
    - - {i18n.t("go.testimonials.adam.name")} - {i18n.t("go.testimonials.adam.title")} -
    -
    - {i18n.t("go.testimonials.adam.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} - {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")}{" "} - {i18n.t("go.testimonials.adam.quoteAfter")} -
    -
    - {/*David*/} -
    -
    - - {i18n.t("go.testimonials.david.name")} - {i18n.t("go.testimonials.david.title")} -
    -
    - {i18n.t("go.testimonials.david.quoteBefore")} {i18n.t("go.testimonials.handle")}{" "} - {i18n.t("go.testimonials.brand.zen")} {i18n.t("go.testimonials.brand.go")}{" "} - {i18n.t("go.testimonials.david.quoteAfter")} -
    -
    - {/*Frank*/} -
    -
    - - {i18n.t("go.testimonials.frank.name")} - {i18n.t("go.testimonials.frank.title")} -
    -
    {i18n.t("go.testimonials.frank.quote")}
    -
    -
    -

    {i18n.t("common.faq")}

    From 40fc406424c27a00f0841af46f6ec96572c973f7 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 16:48:29 +0000 Subject: [PATCH 27/32] ci: make tsgo available for pre-push typechecks --- bun.lock | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/bun.lock b/bun.lock index e8db819e1..8beb9ae6f 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", diff --git a/package.json b/package.json index f2c4dac99..ba84d1052 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "@actions/artifact": "5.0.1", "@tsconfig/bun": "catalog:", "@types/mime-types": "3.0.1", + "@typescript/native-preview": "catalog:", "glob": "13.0.5", "husky": "9.1.7", "prettier": "3.6.2", From 0b825ca383f12fa6649d48165fb3f5e27cc4b049 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 22:07:49 +0000 Subject: [PATCH 28/32] docs: redesign Go pricing graph with horizontal bars and inline request labels Improve visual clarity of request limits on the Go pricing page by replacing dot-based chart with animated horizontal bars that directly show model names and exact request counts. Add proper OpenGraph and Twitter Card meta tags for better social sharing discovery. --- packages/console/app/src/i18n/en.ts | 2 + packages/console/app/src/routes/go/index.css | 254 +++++++++++-------- packages/console/app/src/routes/go/index.tsx | 146 +++++++---- 3 files changed, 242 insertions(+), 160 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 3f39fcd9d..9bf8ad43d 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -246,6 +246,8 @@ export const dict = { "zen.privacy.exceptionsLink": "following exceptions", "go.title": "OpenCode Go | Low cost coding models for everyone", + "go.meta.description": + "Go is a $10/month subscription with generous 5-hour request limits for GLM-5, Kimi K2.5, and MiniMax M2.5.", "go.hero.title": "Low cost coding models for everyone", "go.hero.body": "Go brings agentic coding to programmers around the world. Offering generous limits and reliable access to the most capable open-source models, so you can build with powerful agents without worrying about cost or availability.", diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 34be47f0d..99c61a70b 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -21,6 +21,13 @@ } } +@keyframes go-graph-bar { + to { + opacity: 1; + transform: scaleX(1); + } +} + [data-page="go"] { --color-background: hsl(0, 20%, 99%); --color-background-weak: hsl(0, 8%, 97%); @@ -424,13 +431,78 @@ body { [data-component="limit-graph"] { margin: 0 auto; - max-width: calc(100% - (var(--padding) * 2)); + width: calc(100% - 120px); + max-width: calc(100% - 120px); border: none; background: transparent; - padding: 18px 18px 56px; + padding: 58px var(--padding) 56px; + + @media (max-width: 48rem) { + width: 100%; + max-width: 100%; + } [data-slot="plot"] { position: relative; + overflow: visible; + width: 100%; + margin: 0 auto; + margin-left: -40px; + } + + [data-slot="ylabels"] { + position: absolute; + inset: 0; + pointer-events: none; + } + + [data-slot="ylabels"] [data-ylabel] { + position: absolute; + left: var(--x); + top: var(--y); + transform: translate(-100%, -50%); + color: var(--color-text-strong); + font-size: 16px; + font-weight: 700; + line-height: 1; + white-space: nowrap; + } + + [data-slot="pills"] { + position: absolute; + inset: 0; + pointer-events: none; + + [data-item] { + position: absolute; + left: var(--x); + top: var(--y); + transform: translate(12px, -50%); + display: inline-flex; + align-items: center; + gap: 8px; + border: none; + background: transparent; + height: 20px; + padding: 0 8px; + border-radius: 2px; + max-width: calc(100% - 12px); + font-size: 13px; + line-height: 20px; + box-sizing: border-box; + opacity: 0; + } + + [data-name] { + color: var(--color-text); + white-space: nowrap; + } + + [data-value] { + color: var(--color-text-strong); + font-weight: 600; + white-space: nowrap; + } } [data-slot="plot-labels"] { @@ -451,8 +523,7 @@ body { svg { width: 100%; - height: auto; - aspect-ratio: 720 / 220; + height: 220px; display: block; } @@ -479,13 +550,44 @@ body { font-weight: 600; } + [data-row], + [data-val] { + opacity: 0; + } + + &[data-visible] [data-row], + &[data-visible] [data-val] { + opacity: 1; + transition: opacity 240ms ease; + transition-delay: var(--d, 0ms); + } + [data-stub] { stroke: var(--color-border); - stroke-width: 2; + stroke-width: 1; stroke-linecap: round; opacity: 0.55; } + [data-bar] { + transform-box: fill-box; + transform-origin: left center; + opacity: 0; + transform: scaleX(0.02); + fill: var(--color-go-2); + stroke: none; + } + + [data-bar][data-kind="free"] { + fill: var(--color-text-strong); + } + + [data-val] { + fill: var(--color-text-strong); + font-size: 13px; + font-weight: 650; + } + [data-range] { stroke: var(--color-text-strong); stroke-width: 2; @@ -542,6 +644,17 @@ body { animation-delay: var(--d, 0ms); } + &[data-visible] [data-bar] { + animation: go-graph-bar 560ms cubic-bezier(0.2, 0.7, 0.2, 1) forwards; + animation-delay: var(--d, 0ms); + } + + &[data-visible] [data-slot="pills"] [data-item] { + opacity: 1; + transition: opacity 240ms ease; + transition-delay: var(--d, 0ms); + } + @media (prefers-reduced-motion: reduce) { [data-animate="line"] { stroke-dashoffset: 0; @@ -552,34 +665,49 @@ body { transform: none; animation: none; } + [data-bar] { + opacity: 1; + transform: none; + animation: none; + } + [data-row], + [data-val] { + opacity: 1; + transition: none; + } + + [data-slot="pills"] [data-item] { + opacity: 1; + transition: none; + } } figcaption { margin-top: 34px; display: flex; - flex-direction: column; - gap: 10px; + justify-content: center; font-size: 13px; + text-align: center; } [data-slot="caption-row"] { display: flex; width: 100%; + justify-content: center; } [data-slot="caption-left"] { - display: grid; + display: flex; width: 100%; - grid-template-columns: var(--start, 16.9%) minmax(0, 1fr); - grid-template-rows: auto auto; - align-items: center; - column-gap: 0; - row-gap: 0; min-width: 0; + justify-content: center; } [data-slot="caption-meta"] { - display: contents; + display: flex; + flex-direction: row; + gap: 16px; + align-items: baseline; } [data-slot="caption-label"] { @@ -587,8 +715,6 @@ body { font-weight: 650; white-space: nowrap; line-height: 1; - grid-column: 1; - grid-row: 1; } [data-slot="caption-link"] { @@ -596,73 +722,6 @@ body { text-decoration-thickness: 1px; width: fit-content; line-height: 1; - grid-column: 1; - grid-row: 2; - align-self: start; - } - - [data-slot="legend"] { - display: flex; - width: 100%; - flex-wrap: nowrap; - gap: 10px; - min-width: 0; - overflow-x: auto; - -webkit-overflow-scrolling: touch; - padding-bottom: 8px; - margin-left: -12px; - grid-column: 2; - grid-row: 1; - align-self: center; - - [data-item] { - display: inline-flex; - flex: 0 0 auto; - align-items: center; - gap: 8px; - border: 1px solid var(--color-border-weak); - background: var(--color-background); - padding: 6px 10px; - border-radius: 999px; - max-width: 100%; - } - - [data-dot] { - width: 10px; - height: 10px; - border-radius: 999px; - display: inline-block; - border: 1px solid var(--color-text-strong); - background: var(--color-background); - flex: 0 0 auto; - } - - [data-dot][data-kind="go"] { - background: var(--color-background-interactive); - } - - [data-dot][data-kind="go"][data-model="glm"] { - background: var(--color-go-1); - } - - [data-dot][data-kind="go"][data-model="kimi"] { - background: var(--color-go-2); - } - - [data-dot][data-kind="go"][data-model="minimax"] { - background: var(--color-go-3); - } - - [data-name] { - color: var(--color-text); - white-space: nowrap; - } - - [data-value] { - color: var(--color-text-strong); - font-weight: 600; - white-space: nowrap; - } } [data-slot="caption-note"] { @@ -671,35 +730,8 @@ body { } @media (max-width: 56.25rem) { - [data-slot="caption-left"] { - grid-template-columns: var(--start, 16.9%) minmax(0, 1fr); - grid-template-rows: auto auto; - align-items: start; - } - - [data-slot="legend"] { - grid-column: 2; - grid-row: 1; - } - [data-slot="caption-meta"] { - display: flex; - gap: 24px; - align-items: baseline; - grid-column: 2; - grid-row: 2; - margin-top: 12px; - } - - [data-slot="caption-label"] { - grid-column: auto; - grid-row: auto; - } - - [data-slot="caption-link"] { - grid-column: auto; - grid-row: auto; - align-self: baseline; + gap: 14px; } } } diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 9e4f0eefd..6ae5e476c 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -10,6 +10,7 @@ import { Faq } from "~/component/faq" import { Legal } from "~/component/legal" import { Footer } from "~/component/footer" import { Header } from "~/component/header" +import { config } from "~/config" import { getLastSeenWorkspaceID } from "../workspace/common" import { IconMiniMax, IconZai } from "~/component/icon" import { useI18n } from "~/context/i18n" @@ -49,24 +50,50 @@ function LimitsGraph(props: { href: string }) { { id: "kimi", name: "Kimi K2.5", req: 1850, d: "240ms" }, { id: "minimax", name: "MiniMax M2.5", req: 20000, d: "360ms" }, ] - const ratio = (n: number) => n / free const w = 720 const h = 220 - const left = 88 - const right = 24 - const top = 22 - const bottom = 46 + const left = 40 + const right = 60 + const top = 18 + const bottom = 44 const plot = w - left - right + + const ratio = (n: number) => n / free const rmax = Math.max(1, ...models.map((m) => ratio(m.req))) const log = (n: number) => Math.log10(Math.max(n, 1)) - const x = (r: number) => left + (log(r) / log(rmax)) * plot + const base = 24 + const p = 2.2 + const x = (r: number) => left + base + Math.pow(log(r) / log(rmax), p) * (plot - base) const start = (x(1) / w) * 100 - const yFree = 74 - const yGo = 134 const ticks = [1, 2, 5, 10, 25, 50, 100].filter((t) => t <= rmax) - const y = (n: number) => `${(n / h) * 100}%` + const labels = (() => { + const set = new Set() + let last = -Infinity + for (const t of ticks) { + if (t === 1) { + set.add(t) + last = x(t) + continue + } + const pos = x(t) + if (pos - last < 44) continue + set.add(t) + last = pos + } + return set + })() + const bh = 8 + const gap = 16 + const step = bh + gap + const sep = bh + 40 + const fy = top + 22 + const gy = (i: number) => fy + sep + step * i + const my = models.length < 2 ? gy(0) : (gy(0) + gy(models.length - 1)) / 2 + const px = (n: number) => `${(n / w) * 100}%` + const py = (n: number) => `${(n / h) * 100}%` + const lx = px(left - 16) return (
    -
    - + + +
    @@ -134,22 +190,6 @@ function LimitsGraph(props: { href: string }) { {i18n.t("go.graph.usageLimits")}
    -
    - - - {i18n.t("go.graph.free")} - {free.toLocaleString()} - - - {(m) => ( - - - {m.name} - {m.req.toLocaleString()} - - )} - -
    @@ -165,9 +205,17 @@ export default function Home() {
    {/**/} {i18n.t("go.title")} + - - + + + + + + + + +
    From 6cbb1ef1c233c6579f94552c796d4239781c620a Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 22:10:17 +0000 Subject: [PATCH 29/32] wip: Make bar colors in limit graph customizable via CSS variables for consistent theming across the go route visualization --- packages/console/app/src/routes/go/index.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/console/app/src/routes/go/index.css b/packages/console/app/src/routes/go/index.css index 99c61a70b..0ff04a225 100644 --- a/packages/console/app/src/routes/go/index.css +++ b/packages/console/app/src/routes/go/index.css @@ -427,6 +427,10 @@ body { radial-gradient(1200px 400px at 15% 0%, rgba(255, 255, 255, 0.03), transparent 55%), radial-gradient(900px 320px at 85% 15%, rgba(255, 255, 255, 0.02), transparent 60%), var(--color-background-weak); + + [data-component="limit-graph"] { + --bar-go: #f7ff00; + } } [data-component="limit-graph"] { @@ -436,6 +440,7 @@ body { border: none; background: transparent; padding: 58px var(--padding) 56px; + --bar-go: var(--color-go-2); @media (max-width: 48rem) { width: 100%; @@ -574,7 +579,7 @@ body { transform-origin: left center; opacity: 0; transform: scaleX(0.02); - fill: var(--color-go-2); + fill: var(--bar-go); stroke: none; } From f8685a4d532386b7c30112454a89fc5ab884e7d1 Mon Sep 17 00:00:00 2001 From: David Hill Date: Wed, 4 Mar 2026 22:16:30 +0000 Subject: [PATCH 30/32] tui: clarify free tier includes Big Pickle and promotional requests on Go pricing page --- packages/console/app/src/i18n/en.ts | 1 + packages/console/app/src/routes/go/index.tsx | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/console/app/src/i18n/en.ts b/packages/console/app/src/i18n/en.ts index 9bf8ad43d..5227b3f54 100644 --- a/packages/console/app/src/i18n/en.ts +++ b/packages/console/app/src/i18n/en.ts @@ -258,6 +258,7 @@ export const dict = { "go.cta.price": "$10/month", "go.pricing.body": "Use with any agent. Top up credit if needed. Cancel any time.", "go.graph.free": "Free", + "go.graph.freePill": "Big Pickle and promotional", "go.graph.go": "Go", "go.graph.label": "Requests/5h", "go.graph.usageLimits": "Usage limits", diff --git a/packages/console/app/src/routes/go/index.tsx b/packages/console/app/src/routes/go/index.tsx index 6ae5e476c..eb954bd99 100644 --- a/packages/console/app/src/routes/go/index.tsx +++ b/packages/console/app/src/routes/go/index.tsx @@ -67,7 +67,7 @@ function LimitsGraph(props: { href: string }) { const x = (r: number) => left + base + Math.pow(log(r) / log(rmax), p) * (plot - base) const start = (x(1) / w) * 100 - const ticks = [1, 2, 5, 10, 25, 50, 100].filter((t) => t <= rmax) + const ticks = [1, 5, 10, 25, 50, 100].filter((t) => t <= rmax) const labels = (() => { const set = new Set() let last = -Infinity @@ -162,7 +162,7 @@ function LimitsGraph(props: { href: string }) { + +