Skip to content

Commit 7f56457

Browse files
committed
feat(docs-site): hero product-word drum — Codex/Claude rotateX cylinder
- 4-face inline-grid cylinder in the hero H1, fixed slot width (CLS 0), 12s hold-turn-hold cycle, Claude face in terracotta tint - prefers-reduced-motion collapses to a static 'Codex · Claude' pairing - hero subcopy now names Claude Code alongside Codex (3 locales) - bento: full-width Claude Code cell + docsMap link to the guide
1 parent edf16cb commit 7f56457

2 files changed

Lines changed: 76 additions & 6 deletions

File tree

docs-site/src/components/Landing.astro

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const icons: Record<string, string> = {
4040
rocket: 'M4.5 16.5c-1.5 1.26-2 5-2 5s3.74-.5 5-2c.71-.84.7-2.13-.09-2.91a2.18 2.18 0 0 0-2.91-.09ZM12 15l-3-3a22 22 0 0 1 2-3.95A12.88 12.88 0 0 1 22 2c0 2.72-.78 7.5-6 11a22.35 22.35 0 0 1-4 2Zm-3-3H4s.55-3.03 2-4c1.62-1.08 5 0 5 0m0 9v5s3.03-.55 4-2c1.08-1.62 0-5 0-5',
4141
book: 'M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20',
4242
code: 'M16 18l6-6-6-6M8 6l-6 6 6 6',
43+
terminal: 'M4 17l6-6-6-6M12 19h8',
4344
folder: 'M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z',
4445
};
4546
@@ -89,6 +90,7 @@ const docsMap = [
8990
{ label: t('Model Routing', '모델 라우팅', '模型路由'), href: `${prefix}guides/model-routing/` },
9091
{ label: t('Codex Integration', 'Codex 통합', 'Codex 集成'), href: `${prefix}guides/codex-integration/` },
9192
{ label: t('Codex App Model Picker', 'Codex App 모델 선택기', 'Codex App 模型选择器'), href: `${prefix}guides/codex-app-models/` },
93+
{ label: 'Claude Code', href: `${prefix}guides/claude-code/` },
9294
{ label: t('Sidecars: Search & Vision', '사이드카: 검색 & 비전', '边车:搜索与视觉'), href: `${prefix}guides/sidecars/` },
9395
{ label: t('Web Dashboard', '웹 대시보드', '网页控制台'), href: `${prefix}guides/web-dashboard/` },
9496
{ label: t('Sub-agent Surface', '서브에이전트 서피스', '子代理界面'), href: `${prefix}guides/sub-agent-surface/` },
@@ -129,12 +131,25 @@ const docsMap = [
129131
<Image src={heroFieldDark} alt="" class="lp-field-dark" loading="lazy" widths={[1024, 2048]} sizes="100vw" />
130132
</div>
131133
<div class="lp-hero-copy">
132-
<h1 id="_top">{t('Run Codex on any LLM.', 'Codex를 어떤 LLM 위에서든.', '让 Codex 跑在任意 LLM 上。')}</h1>
134+
{/* Product-word drum: the H1 performs the claim — the proxy serves both
135+
Codex and Claude Code. 4-face rotateX cylinder, fixed slot width via
136+
inline-grid stacking; reduced-motion collapses to a static pairing. */}
137+
<h1 id="_top">
138+
{t('Run ', '', '')}<span class="lp-drum" aria-label="Codex and Claude">
139+
<span class="lp-drum-spin" aria-hidden="true">
140+
<span class="lp-drum-face lp-drum-codex">Codex</span>
141+
<span class="lp-drum-face lp-drum-claude">Claude</span>
142+
<span class="lp-drum-face lp-drum-codex">Codex</span>
143+
<span class="lp-drum-face lp-drum-claude">Claude</span>
144+
</span>
145+
<span class="lp-drum-static" aria-hidden="true">Codex<span class="lp-drum-dot"> · </span>Claude</span>
146+
</span>{t(' on any LLM.', '를 어떤 LLM 위에서든.', ' 跑在任意 LLM 上。')}
147+
</h1>
133148
<p class="lp-sub">
134149
{t(
135-
'opencodex is a local proxy that translates the Codex Responses API to any provider wire format streaming, tool calls, reasoning, and images, in both directions. Zero Codex patches.',
136-
'opencodex는 Codex의 Responses API를 어떤 프로바이더 wire 포맷으로든 양방향 변환하는 로컬 프록시입니다 — 스트리밍, tool call, reasoning, 이미지까지. Codex 패치는 없습니다.',
137-
'opencodex 是一个本地代理, Codex 的 Responses API 双向翻译为任意 provider 的线路格式 —— 包括流式、工具调用、推理与图像。无需修补 Codex'
150+
'opencodex is a local proxy that serves Codex and Claude Code from one port — translating each wire format to any provider, with streaming, tool calls, reasoning, and images in both directions. Zero client patches.',
151+
'opencodex는 포트 하나로 Codex와 Claude Code를 함께 서빙하는 로컬 프록시입니다 — 각 wire 포맷을 어떤 프로바이더로든 양방향 변환하고, 스트리밍·tool call·reasoning·이미지까지 그대로 통과시킵니다. 클라이언트 패치는 없습니다.',
152+
'opencodex 是一个本地代理,用同一个端口同时服务 Codex 与 Claude Code —— 将各自的线路格式双向翻译为任意 provider,支持流式、工具调用、推理与图像。无需修补客户端'
138153
)}
139154
</p>
140155
<div class="lp-cta">
@@ -246,6 +261,14 @@ const docsMap = [
246261
'为 Codex spawn_agent 固定最多五个路由或原生模型,并全局切换 v1 / base / v2 界面。'
247262
)}</p>
248263
</article>
264+
<article class="lp-cell lp-cell-claude">
265+
<h3><svg class="lp-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d={icons.terminal} /></svg>Claude Code</h3>
266+
<p>{t(
267+
'ocx claude launches Claude Code against the same port — every routed model in the /model picker, auto-context up to 1M, roster sub-agents, and your claude.ai login stays active.',
268+
'ocx claude가 같은 포트로 Claude Code를 띄웁니다 — 라우팅된 모든 모델이 /model 선택기에 뜨고, 최대 1M auto-context, 로스터 서브에이전트, claude.ai 로그인은 그대로 유지됩니다.',
269+
'ocx claude 让 Claude Code 连接同一端口 —— 所有路由模型出现在 /model 选择器中,auto-context 最高 1M,roster 子代理,claude.ai 登录保持不变。'
270+
)}</p>
271+
</article>
249272
<article class="lp-cell">
250273
<h3><svg class="lp-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d={icons.search} /></svg>{t('Search & vision sidecars', '검색 & 비전 사이드카', '搜索与视觉边车')}</h3>
251274
<p>{t(

docs-site/src/styles/custom.css

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,50 @@ main:has(.lp) .content-panel:first-child { padding-block: 0; }
346346
:root[data-theme='light'] .lp-sub { color: rgba(247, 245, 242, 0.82); }
347347
:lang(ko) .lp-hero-copy h1, :lang(zh-CN) .lp-hero-copy h1 { word-break: keep-all; }
348348
:lang(ko) .lp-sub, :lang(zh-CN) .lp-sub { word-break: keep-all; }
349+
350+
/* hero product-word drum: a 4-face rotateX cylinder cycling Codex -> Claude.
351+
The inline-grid stacks every face in one cell, so the slot width equals the
352+
widest word and the sentence never shifts (CLS 0). Faces sit on a prism
353+
(rotateX steps of 90deg around a shared axis); the drum turns -360deg per
354+
cycle with holds so each word is readable. */
355+
.lp-drum {
356+
display: inline-grid;
357+
position: relative;
358+
vertical-align: baseline;
359+
perspective: 24rem;
360+
}
361+
.lp-drum-spin {
362+
grid-area: 1 / 1;
363+
display: inline-grid;
364+
justify-items: center;
365+
transform-style: preserve-3d;
366+
animation: lp-drum-turn 12s cubic-bezier(0.65, 0, 0.35, 1) infinite;
367+
}
368+
.lp-drum-face {
369+
grid-area: 1 / 1;
370+
backface-visibility: hidden;
371+
/* r = (line box height / 2) / tan(45deg); 0.56em keeps adjacent faces from
372+
poking through the visible one at this line-height. */
373+
transform: rotateX(0deg) translateZ(0.56em);
374+
}
375+
.lp-drum-face:nth-child(2) { transform: rotateX(-90deg) translateZ(0.56em); }
376+
.lp-drum-face:nth-child(3) { transform: rotateX(-180deg) translateZ(0.56em); }
377+
.lp-drum-face:nth-child(4) { transform: rotateX(-270deg) translateZ(0.56em); }
378+
.lp-drum-claude { color: #e08b6d; }
379+
:root[data-theme='light'] .lp-drum-claude { color: #f0a284; }
380+
.lp-drum-static { display: none; grid-area: 1 / 1; }
381+
.lp-drum-static .lp-drum-dot { opacity: 0.45; }
382+
@keyframes lp-drum-turn {
383+
0%, 21% { transform: rotateX(0deg); }
384+
25%, 46% { transform: rotateX(90deg); }
385+
50%, 71% { transform: rotateX(180deg); }
386+
75%, 96% { transform: rotateX(270deg); }
387+
100% { transform: rotateX(360deg); }
388+
}
389+
@media (prefers-reduced-motion: reduce) {
390+
.lp-drum-spin { display: none; }
391+
.lp-drum-static { display: inline; }
392+
}
349393
.lp-cta {
350394
display: flex;
351395
align-items: center;
@@ -613,6 +657,7 @@ main:has(.lp) .content-panel:first-child { padding-block: 0; }
613657
"prov prov pick"
614658
"auth pool pick"
615659
"sub side pick"
660+
"cl cl cl"
616661
"term term term";
617662
gap: 0.875rem;
618663
}
@@ -659,10 +704,11 @@ main:has(.lp) .content-panel:first-child { padding-block: 0; }
659704
/* asymmetric slab: image cell runs tall down the right rail */
660705
.lp-cell-providers { grid-area: prov; }
661706
.lp-cell-picker { grid-area: pick; }
707+
.lp-cell-claude { grid-area: cl; }
662708
.lp-grid > .lp-cell:nth-child(2) { grid-area: auth; }
663709
.lp-grid > .lp-cell:nth-child(3) { grid-area: pool; }
664710
.lp-grid > .lp-cell:nth-child(5) { grid-area: sub; }
665-
.lp-grid > .lp-cell:nth-child(6) { grid-area: side; }
711+
.lp-grid > .lp-cell:nth-child(7) { grid-area: side; }
666712
.lp-cell-picker img {
667713
max-height: none;
668714
height: 100%;
@@ -682,14 +728,15 @@ main:has(.lp) .content-panel:first-child { padding-block: 0; }
682728
"auth pool"
683729
"pick sub"
684730
"pick side"
731+
"cl cl"
685732
"term term";
686733
}
687734
.lp-quick { grid-template-columns: 1fr; }
688735
}
689736
@media (max-width: 40rem) {
690737
.lp-grid {
691738
grid-template-columns: 1fr;
692-
grid-template-areas: "prov" "auth" "pool" "pick" "sub" "side" "term";
739+
grid-template-areas: "prov" "auth" "pool" "pick" "sub" "side" "cl" "term";
693740
}
694741
.lp-cell-picker img { max-height: 22rem; height: auto; }
695742
.lp-cta { flex-direction: column; width: 100%; }

0 commit comments

Comments
 (0)