Skip to content

Agentaily Design System

Agentaily 是一个 AI chatbot。品牌一句话,原文照录:极客风格,简约,大气,科技感(geek-flavored, minimal, expansive, technological)。Agentaily 先用平实的语言回答,再展示推导:结论 → 推导,不浮夸,不卖萌。

这是一个全新起步(greenfield)的系统 —— 没有提供任何代码库、Figma 或既有素材。这里的一切(名称、品牌标、配色、字体、组件、屏幕)都是本项目在 2026-06-10 原创的,也是真相源。唯一的输入是那句一行品牌一句话,以及启动问卷里的这些选择:双主题(暗色默认)、单色 accent,其余一概交由设计自定。

两个产品界面被表达为完整的 UI 套件:

  • Chat app(ui_kits/chat/)—— 核心产品:侧栏 + thread + composer。
  • Marketing website(ui_kits/website/)—— 落地页。
  • Documentation site(ui_kits/docs/)—— 三栏开发者文档(nav + article + TOC)。

组件库是刻意做到穷尽的 —— 11 个类别共 117 个导出,覆盖完整的 shadcn/ui 原语集,外加 AI 原生界面(reasoning、tool calls、agents、voice、workflow graphs)。见下方 INDEX。


CONTENT FUNDAMENTALS

语气: 平实、精确、略带干燥。靠克制传递自信 —— Agentaily 从不推销,只陈述。一位优秀资深工程师的声音:短陈述句、具体数字、零填充词。

语言: 设计上即双语。Display/英文承载技术身份("Reasoning, distilled"),正文文案用自然中文(「先给结论,再给推导——不废话,不卖萌」)。混用是有意为之,但在同一个元素内只选一种语言。

大小写:

  • 产品文案与按钮:sentence case —— "New chat"、"Start free"、"Read the docs"。
  • 标签母题:mono ALL-CAPS 带字距 —— CONVERSATIONSAGENTAILY MAY MAKE MISTAKES
  • 字标永远小写:agentaily

人称: 用 你/you 称呼用户;Agentaily 称自己为 Agentaily,绝不说 "I'm excited to…"。系统文本是无人称的:"This cannot be undone."

Emoji:绝不用。 状态由方点和颜色 token 承载。键盘符号(⌘ ⌥ ⇧ ⏎)和几何 unicode(▣ ▍)是当作文本打出来的,而且这套词汇的一部分。

数字即文案。 "0.4s"、"128k"、"Retry in 18s" —— 用具体数字替代形容词。

例 —— ✓ "Rate limited. Retry in 18s." ✗ "Oops! Something went wrong 😅" · ✓ "有什么要解决的?" ✗ "✨ 开启你的奇妙旅程!"


VISUAL FOUNDATIONS

颜色。 单色优先。两套阶:paper(亮色,:root 上的默认)和 ink(暗色,限定在 [data-theme="dark"] 下)。accent 是反相,不是色相 —— primary 按钮在暗色下白底黑字、在亮色下黑底白字。语义绿/琥珀/红(--ok/--warn/--danger)存在,但只作为状态出现;绝不装饰。除点阵 mask fade 外任何地方都没有渐变。

字体。 Space Grotesk(display + UI)和 JetBrains Mono(代码、时间戳、标签)。CJK 回退到系统 sans(PingFang SC / Microsoft YaHei)。display 尺寸用紧字距(−0.02em)、中等字重 —— 绝不 bold-black。mono ALL-CAPS 标签(12px,+0.08em)是这套系统的招牌。正文 15px/1.6,最大约 76ch。

间距。 4px 栅格。外部空间宽裕(区块 72–96px)—— 大气;内部节奏紧凑(8–16px)—— 极客。聊天 thread 列最大 760px;营销容器 1120px;侧栏固定 272px。

背景。 取自色阶的平涂纯色。无摄影、无插画。唯一允许的纹理:点阵(24px,用于 hero/空态,通常带 mask fade)与 hairline 分隔线。营销 hero 的主视觉就是产品窗口本身。

圆角。 硬边:2px chips、4px buttons/inputs、8px cards/dialogs。只有罕见的头像情形才用全圆;默认头像是方的(4px)。

边框与阴影。 层级来自 1px hairline(--line-1 静止、--line-2 hover/强),不靠阴影。阴影只为浮层存在(菜单 --shadow-2,dialogs/营销窗口 --shadow-3)。除 Kbd 的 2px 底边框外无内阴影。

Hover: 背景填充(--bg-3)或边框升级(--line-1--line-2)—— 绝不对文字做透明度淡化。Press: translateY(1px) —— 机械感、不缩放。Focus: 键盘焦点用双环(--ring);输入框用 border-color 互换。

动效。 一条缓动(cubic-bezier(0.2,0,0,1)),三档时长(120/200/320ms)。决断且阻尼 —— 无回弹、无视差。定义品牌的机械例外:光标在 steps(1) 闪烁,spinner 在 steps(8) 旋转。尊重 prefers-reduced-motion

透明与模糊: 只在浮层上 —— dialog 蒙层(--bg-overlay + 12px 模糊)和粘性营销 nav。绝不用于内容。

Cards: 平涂 --bg-2、1px --line-1、8px 圆角、无阴影。特色卡可带 corner-tick 母题(对角两枚 L 形刻线)。

母题(每视图用 1 个,最多 2 个): block cursor ▍(活性)· 点阵(潜在空间)· corner ticks(选中/精确)· mono ALL-CAPS 标签。

Chat 解剖: 用户回合是右对齐的 hairline 卡(最大 78%);assistant 回合是 mono AGENTAILY 标签下的整宽 prose —— 没有气泡。流式 = 闪烁的 block cursor。


ICONOGRAPHY

  • 系统:Lucide —— 24px 栅格、stroke 2、round caps、currentColor,渲染在 14–20px。选它是因为这套开源集匹配 hairline 美学。没有现成的品牌图标字体(greenfield);这次替代在 CAVEATS 里标注。
  • 在静态 HTML 中: 从 CDN 加载 UMD 构建(https://unpkg.com/lucide@latest/dist/umd/lucide.js),在 <i data-lucide="plus"> 元素上调 lucide.createIcons() —— 见 guidelines/iconography.card.html
  • 在 React 套件中:ui_kits/chat/ChatIcons.jsx 里的 ChatIcon —— Lucide 路径几何的内联拷贝(plus、search、settings、sun、moon、pen、trash、copy、refresh、chevron-down、x、paperclip、panel-left、arrow-up、message、share)。加图标要从 Lucide 拷贝路径,绝不徒手画。
  • 绝不: 填充图标、双色、emoji 当图标、混用 stroke 粗细。
  • Unicode 作 UI: ⌘ ⌥ ⇧ ⏎ 用在 Kbd;▣ 作 model-chip 字形;✕ 作 dismiss;✓ 用在复制确认里。这些是文本,设为 mono。
  • Logo: assets/logo/agentaily-mark-{white,black}.svg —— cursor-block-in-corner-ticks 品牌标。字标是打出来的、不是画出来的:小写 mono agentaily + 可选的闪烁光标。

INDEX

路径是什么
styles.css全局入口 —— @import 下面的一切。只链这一个文件。
tokens/colors.cssInk + paper 阶、accent、语义色、别名
tokens/typography.css字族、尺度(12–68px)、字重、字距
tokens/spacing.css4px 尺度 + 布局常量
tokens/effects.css圆角、阴影、动效、focus ring、模糊
tokens/base.cssBody 默认值 + 母题工具类(.ax-label, .ax-cursor, .ax-dotgrid, .ax-ticks)
tokens/fonts.cssGoogle Fonts 引入(替身 —— 见 CAVEATS)
assets/logo/品牌标 SVG(白/黑)
guidelines/17 张样例卡(Colors ×4、Type ×4、Spacing ×5、Brand ×4)
states/5 个交互状态矩阵(buttons、form controls、selection/nav、loading/streaming、status/feedback)—— 强制渲染 hover/focus/active/disabled
components/buttons/Button, IconButton, ButtonGroup
components/inputs/Input, Textarea, Select, Switch, Checkbox, Label, RadioGroup, Slider, Toggle, ToggleGroup, Field, FieldGroup, InputGroup, InputOTP, Combobox, Calendar, DatePicker, Form (+FormActions, Form.useForm), SecretField
components/display/Card, Badge, Avatar, Tabs, Kbd, Separator, Skeleton, Progress, Accordion, Breadcrumb, Table, Pagination, Empty, Collapsible, Item, Carousel, Chart (BarChart/LineChart), DataTable, Typography (Prose/Text), StatusPill
components/feedback/Spinner, Toast, Tooltip, Dialog, Alert
components/overlay/Popover, DropdownMenu, Command, Sheet, HoverCard, ContextMenu, Menubar, NavigationMenu, AlertDialog
components/layout/AspectRatio, ScrollArea, Resizable, Sidebar, AppShell, DesignerShell, DocsLayout, PanelSheet, SettingsSheet, PageSection, PanelFooter, SettingsSaveBar —— 含整页 shells/frames + 全屏 rise-up 浮层外壳、构建其上的浮动设置页、逐分区内容布局(eyebrow/title/description + body)、它可选的 footer-content 组件、以及逐 tab 保存条
components/chat/Message, Composer, CodeBlock, ConversationThread, Markdown, ChatApp
components/ai/Reasoning, ToolCall, Sources + Citation, Suggestion/Suggestions, ModelSelector, Attachments, Shimmer, Conversation, Task, Plan, Context, Confirmation, Checkpoint, Queue
components/code/Terminal, FileTree, Snippet, StackTrace, TestResults, Artifact, WebPreview, Agent, Commit, EnvironmentVariables, PackageInfo, Sandbox, SchemaDisplay, JSXPreview, PreviewWorkbench
components/voice/AudioPlayer, MicSelector, VoiceSelector, SpeechInput, Transcription, Persona
components/workflow/Flow (Canvas), Canvas, Node, Edge, Connection, Controls, Panel, Toolbar
components/utilities/Image, OpenInChat, Icon (unified Lucide set), BrandMark, RotatingTagline
components/settings/TestRow, HelpSteps, ConnectionCard, DeepSeekCard —— 连接卡原语 + 共享连接卡外壳(构建在 Card 之上)+ 一张纯展示服务卡
components/auth/AuthDialog (+ AuthDialog.useAuth), AccountControl, SignInPage, VerifyEmailPage (+ VerifyEmailPage.useVerify) —— 登录/注册弹窗 + 持久化 session + 顶栏账户菜单 + 整页登录 + 整页邮箱验证
components/review/MarkupLayer —— 点选元素式 review 浮层(data-mk-label)
Hooks(headless)Queue.useQueue, AuthDialog.useAuth, VerifyEmailPage.useVerify, Form.useForm / Form.useFieldArray —— 只有逻辑、没有 UI,作为静态属性挂在配对组件上
ui_kits/chat/聊天 app(可交互)
ui_kits/website/营销落地页
ui_kits/docs/文档站(可交互)
SKILL.mdAgent-skill 入口

每个组件 ship <Name>.jsx + <Name>.d.ts(props)+ <Name>.prompt.md(用法)—— 跨原语类别(buttons、inputs、display、feedback、overlay、layout、chat、ai、code、voice、workflow、utilities)外加产品域图层(settings、auth、review)共 150 个组件导出。整页 frames —— AppShell / DesignerShell / DocsLayout / PanelSheet / SettingsSheet(layout)、ConversationThread / ChatApp(chat)、SignInPage(auth)—— 是活组件,不是拷贝模板:改一个,每个消费项目在 re-sync 时都受益。经编译好的 bundle 消费:window.AxiomDesignSystem_7fc962。逐组件读它的 .prompt.md 获取可复制粘贴的用法。

两个浮层外壳,别混淆: Sheet(overlay/)是边缘抽屉(从右/左/底以约 420px 在模糊蒙层上滑入);PanelSheet(layout/)是全屏 rise-up 浮层(覆盖视口、淡入蒙层、升起面板,bar + 滚动正文 + 可选粘性 footer)。PanelSheet 是浮层外壳 CSS(.ax-psheet*)的唯一来源 —— 下游凡是拷过 .s-overlay/.s-modal/.s-wrap 外壳的代码都该删掉它、挂上 <PanelSheet>

设置链逐层嵌套,每层都构建在它下面那层之上: PanelSheet(浮动外壳:Header + 可选 Footer 槽)→ SettingsSheet(PanelSheet 上的浮动设置页:左侧分区导航 + 右侧内容)→ 一个你自己组合的 「集成」 分区(如一个 PageSection hero)→ 经 children 落进分区里的连接(DeepSeekCard, …)。PanelFooter 是你传给某个 sheet 的 footer 槽的可选 footer-content 组件(status-left / actions-right)。SettingsSaveBar 是逐 tab 的底部保存条(GitHub 模型 —— 显式提交,不是自动保存):每个设置 tab 底部一条,受 dirty 门控,与 Form.useForm 配对(或对连接分区这类非表单内容用显式 dirty/onSave)。每一层都可单独复用 —— PanelSheet 给任何全屏面板用,SettingsSheet 给任何浮动设置页用,单张卡给一个连接用。左导航项(集成 / 通用 / 账户 …)由消费方经 SettingsSheetnav prop 配置。

Settings architecture (规则速查)

PanelSheet                         浮层外壳:Header + body + 可选 Footer 槽
  └ SettingsSheet                  设置页:左侧分区导航(nav) + 右侧内容 + footer 槽
      ├ 内容(按 active tab 切换):
      │   ├ 集成   PageSection ── 眉标 + 标题 + 正文,连接卡作为 children
      │   │            └ DeepSeekCard ── 组合 ConnectionCard(← built on Card)
      │   └ 通用/账户/…   PageSection(眉标+标题+描述)+ Form.useForm + Input/Select/… 字段
      └ footer  SettingsSaveBar     每个 tab 一条,按 active tab 计算(composes PanelFooter)
  • 集成分区不基于 Form.useForm. 连接卡有掩码密钥(留空=不变)+ 独立的「测试连接」动作,所以用各卡片自己的受控状态,通过显式 dirty(cfg vs savedCfg)接 SettingsSaveBar(传 dirty/saving/onSave/onReset)。
  • 普通设置 tab 基于 Form.useForm. 下游用我们的输入组件 + Form.useForm 自拼字段,footer 放 <SettingsSaveBar form={form} onSave={persist}>,保存条自动读 isDirty/isValid/isSubmitting、先校验再提交;form.reset(values) 把已存值变成新基线。
  • 保存粒度 = 每个 tab 一条底栏(GitHub 模型,显式提交)。footeractive 计算,无需保存的 tab 传 footer={null}
  • 「测试连接」≠ 保存 —— Test 只验证连通性,落库发生在 footer 的「保存」。
  • 想要"改完即存"(自动保存)也支持:不用 SettingsSaveBar,在 onChange 里(防抖)直接持久化,需要的话用 PanelFooter 放个"已保存"状态。系统两种都行,默认推荐显式保存
  • 每个分区的「眉标 + 标题 + 描述 + 正文」用 PageSection —— 通用页面分区布局(不限于设置),集成/通用/账户共用同一头部(集成分区就是一个装着连接卡的 PageSection)。SettingsSection 作为别名保留。

表单是分层的,不是铁板一块。 展示型控件(Input/Select/Field…)自持布局,绝不依赖某个表单引擎。Form + FormActions 只加纯结构。Form.useForm 是一个可选、零依赖的编排 hook(values/errors/touched/validate/submit),作为大写 Form 导出上的静态属性暴露 —— 把它换成 react-hook-form 或 TanStack,控件照样能用。错误只在 blur 或 submit 之后浮现;把 form.field(name) 展开到任何值控件上,或对布尔控件用 form.field(name, {type:"checkbox"})

ARCHITECTURE — 分层与复用 (layering & reuse)

这套系统坐落在两条正交的轴上。别把它们混为一谈:一个域(domain)不是一个层(layer)

① 纵向 — 抽象层(依赖只向下指)

是什么依赖
L0 Tokens颜色 / 字体 / 间距 / 圆角 / 阴影 / 动效 变量tokens/*.css
L1 Primitives(atoms)无业务含义、随处可用tokensButton, Input, Badge, Icon, BrandMark, RotatingTagline
L2 Composites(molecules)几个原语组合;仍跨产品L1Composer, SecretField, StatusPill
L3 Patterns(organisms)自包含交互 + 状态、可配置L1–L2AuthDialog, MarkupLayer, ConversationThread, DeepSeekCard(纯展示 —— 状态归调用方)
L4 Page shells / frames带 slot 的整页布局L1–L3AppShell, DesignerShell, DocsLayout, SignInPage, VerifyEmailPage, PanelSheet(浮动外壳)→ SettingsSheet(其上的设置页)
L5 Product code真实内容 + 业务逻辑 —— 绝不放在 DS 里L4各 app 的 flow / preview 渲染器

② 横向 — 域(层内部的分类,不是一个级别)

buttons · inputs · display · feedback · overlay · layout · chat · ai · code · voice · workflow · utilities · settings · auth · review。一个产品域组件(如 DeepSeekCard)生活在它的抽象层,只是被归档在它的域文件夹(settings/)下。域是文件夹,不是分级。

一个组件该放哪? 问:(1) 它依赖什么?—— 组合 + 自持状态 → 更高。(2) 被 ≥2 个界面复用?—— 如果没有,就留在 app 里,别放 DS。(3) 业务含义有多重?—— 越重 → 越高层,越通用 → 越低层。

复用类型与传播 (reuse types & propagation)

类型机制上游改动会传播吗?
Tokens ①、全局/母题 class ②、组件 ③引用 —— 运行时加载链接的 styles.css + _ds_bundle.js —— 重新 sync 绑定,每个消费方都更新(单一真相源)
模板(templates/<slug>/)拷贝 / fork —— 文件夹被拷进消费项目不会 —— 拷贝时即冻结;不过拷贝仍活链接 token + 组件,所以它的颜色/按钮会更新、它的布局不会

原则:有共享就「上移」成组件,而不是复制 (share by moving up)

为了内部统一,把任何共享的东西上移进一个组件(活的、单一来源)—— 而不是塞进模板。模板是一次性脚手架,本就是用来 fork 和分叉的。这正是为什么 designer shell 和原先的 starters/ 页面现在以组件形态存在(AppShell, DesignerShell, DocsLayout, SettingsSheet, ConversationThread, SignInPage):修一次外壳,每个项目在 re-sync 时都受益。让分层不腐烂的那条唯一规则:依赖严格单向向下 —— 低层永不向上够取。

Headless hooks(逻辑层 — 只有逻辑、没有 UI)

有些逻辑值得复用而不必拖着某个特定 UI 一起。它以 headless hook 形态发布,作为静态属性挂在与它配对的大写组件上(镜像 Form.useForm)。hook 持有状态;组件只负责渲染。 调用方持有这个 hook 并注入它(如 <ConversationThread controller={q} />),所以一份状态能同时驱动多处 UI —— 一个 composer、一个发布按钮、一个 markup layer 全都能共用同一个 Queue.useQueue

Hook返回配对
Queue.useQueue({ onFirst, onBatch }){ queue, busy, enqueue, remove, reset } —— 忙时仍可继续发送的缓冲区<Queue>, ConversationThread controller
AuthDialog.useAuth(storageKey?){ user, signIn, signOut } —— localStorage 持久化的 session<AuthDialog>, <AccountControl>
VerifyEmailPage.useVerify({ verifyToken }){ status, error, retry } —— verifying → ok / error 流程跑手(throw/网络 → error)<VerifyEmailPage>
Form.useForm(config)受控表单编排(values/errors/touched/validate/submit)各输入控件
Form.useFieldArray({ form, name })动态列表字段(append/remove/move…)Form

这就是 headless 模式(React Aria / Downshift / TanStack):把逻辑与渲染拆开、在下游组合。把可复用的胶水也留在上游 —— 如果每个消费方都以同样方式接 hook + 组件,就加一个便利封装;如果接法确实不同(如每个 app 的 renderTurn 回合映射),就把它留在下游。Headless hooks 自成一层(在 Design System tab 下的 Hooks 里可浏览),不埋在组件内部。

CAVEATS

  • 字体是 CDN 替身: Space Grotesk + JetBrains Mono 经 Google Fonts @import(不 ship 任何二进制)。离线/生产使用请把 tokens/fonts.css 换成真正的 @font-face + 字体文件。
  • 图标是 Lucide(CDN / 拷贝路径),不是定制集。
  • 套件里所有产品文案、数据和名字都是杜撰的占位符。