Astryx Butter 主题深度指南:暖金色设计系统主题的安装、配置与调色板再生成
【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx
导读
@astryxdesign/theme-butter是开源设计系统 Astryx 官方发布的主题包之一,以"温暖的金黄色 + 清爽的蓝色点缀"为核心视觉语言,专为消费级界面场景设计:足够俏皮、又能保持可读性。本文将完整讲解该主题的安装接入、运行时挂载方式、21 步色调色板与语义色角色、字体排版体系,并深入其源码与生成脚本,带你理解调色板如何由 CIELab → HCT 算法平滑生成、组件级覆盖如何落地,从而具备自定义与再生成该主题的实战能力。
主题概览
Butter 主题的定位在 package.json 中有明确描述:"Warm, creamy yellows with a friendly blue accent. Playful enough for consumer surfaces, soft enough to stay readable."(温暖奶油黄 + 友好蓝色点缀,对消费者界面足够俏皮,对可读性足够柔和)。
- 展示字体(Display):Sarina(手写体),仅用于页级大标题
- 标题与正文(Heading & Body):Outfit,基准 14px、比例 1.25
- 代码字体(Code):JetBrains Mono
- 强调色(Accent):品牌蓝
#225BFF,暗色模式下切换为黄油黄#FDEE8C
该主题基于 Astryx Core 的defineThemeAPI 定义,产物包含编译后的theme.css、运行时主题对象与图标注册表,可通过XDSTheme组件挂载到任意 React 应用中。
安装
使用 npm(或 pnpm / yarn)安装主题包,同时需要安装其 peer 依赖@astryxdesign/core与react:
npm install @astryxdesign/theme-butter从 package.json 可以看到版本约束:
peerDependencies:@astryxdesign/core@0.6.0、react@>=19dependencies:lucide-react@^1.18.0(图标组件来源)devDependencies:@astryxdesign/cli@0.6.0(用于astryx theme build编译 CSS)
包的exports字段提供了三个子路径入口:
| 导入路径 | 内容 |
|---|---|
@astryxdesign/theme-butter | 源码入口(dist/source.js/dist/source.mjs),同时导出butterTheme、butterPalettes与butterIconRegistry |
@astryxdesign/theme-butter/built | 编译后的主题对象(dist/butter.js),供XDSTheme直接消费 |
@astryxdesign/theme-butter/theme.css | 编译生成的静态 CSS(dist/theme.css) |
快速接入:在 React 应用中挂载 Butter 主题
主题通过 Astryx 的运行时组件XDSTheme挂载。官方推荐的用法是导入built子路径下的butterTheme,并同时引入theme.css,保证在 JavaScript 运行前样式就已就位:
import {butterTheme} from '@astryxdesign/theme-butter/built'; import {XDSTheme} from '@astryxdesign/core/theme'; import '@astryxdesign/theme-butter/theme.css'; function App() { return <XDSTheme theme={butterTheme}>{/* Your app content */}</XDSTheme>; }要点说明:
- 为什么用
/built而非根入口:根入口导出的是 TS 源码打包产物(含调色板数据等),/built则是为运行时优化后的主题对象,避免把不必要的元数据带进最终包体; theme.css必须在文档头加载:它由 CLI 编译生成,包含全部 CSS 变量与组件样式,提前引入可避免主题样式闪烁(FOUC);- Sarina 与 Outfit 依赖 Google Fonts:README 明确建议在文档
<head>中手动添加对应的<link rel="stylesheet">预加载字体,避免运行时按需拉取字体造成布局抖动。
色彩体系:源调色板与 21 步色调色板
源色(Source Palette)
Butter 的设计源头是以下六个品牌色,其中 Accent 即品牌蓝,暗色模式的主题强调色则切换为黄油黄:
| Role | Hex |
|---|---|
| Accent | #225BFF |
| Yellow | #FDEE8C |
| Error | #FC473B |
| Warning | #FFC502 |
| Success | #91D143 |
| Info | #4883FD |
21 步色调色板(butterPalettes)
从 butterTheme.ts 可以看到,Blue、Cyan、Green、Orange、Pink、Purple、Red、Teal、Yellow 九个分类色,加上 Error / Warning / Success 三个语义色,每一个都被发布为一套平滑的 21 步色调色板(tone 从 0 到 100,步长 5),统一挂在butterPalettes导出下。例如 Blue 色板的提取片段:
blue: { 0: '#000000', 5: '#001041', 10: '#001b4c', 15: '#002558', 20: '#062f63', 25: '#203a6c', 30: '#324575', ... 85: '#cbd3f9', 90: '#dbe1ff', 95: '#edf0ff', 100: '#ffffff', }语义色角色:T90 / T80 / T25 三分法
分类徽章(Categorical badges)、卡片(cards)与横幅文本(banner text)角色统一从这些色板中读取,遵循固定的明暗两套取值约定:
T90(浅色模式)/T15(暗色模式):背景表面(background surfaces)T80(浅色模式)/T25(暗色模式):边框、暗色模式文本(borders, dark-mode text)T25(浅色模式)/T80(暗色模式):浅色模式文本、图标(light-mode text, icons)
这一点在butterTheme.ts的 categorical 区域得到印证:每个分类色的--color-background-*、--color-border-*、--color-text-*/--color-icon-*都取自同一色板的不同音阶。例如 Blue 分类:
'--color-background-blue': ['#dbe1ff', '#dbe1ff'], // T90 '--color-border-blue': ['#bdc5eb', '#bdc5eb'], // T80 '--color-icon-blue': ['#203a6c', '#203a6c'], // T25 '--color-text-blue': ['#203a6c', '#203a6c'], // T25值得注意的设计决策:分类色在明暗两种模式下使用完全相同的值(浅色模式的柔和粉彩背景 + 深色文字同样适用于暗色模式),这与中性色/强调色在明暗模式下互换音阶的做法不同,属于刻意保留的"curated dark mode"。
语义状态色与徽章
状态语义在 light / dark 两侧同样遵循 T25 / T80 约定,例如:
'--color-error': ['#771210', '#ffb4a6'], '--color-warning': ['#543700', '#f7be00'], '--color-success': ['#004700', '#99d94b'],而徽章(badge)的语义变体则直接钉死品牌色以获得高辨识度的 vivid 填充,例如variant:info使用#4883fd(而非品牌蓝#225BFF)、variant:error使用#fc473b、variant:success使用#91D143、variant:warning使用#ffc502,variant:neutral则用黄油黄背景 + 品牌蓝文字。
排版体系:Sarina × Outfit × JetBrains Mono
从 butterTheme.ts 的typography配置可以看到完整定义:
typography: { scale: {base: 14, ratio: 1.25}, body: { family: 'Outfit', fallbacks: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif', }, heading: { family: 'Outfit', fallbacks: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif', weights: {3: 'bold', 4: 'bold'}, }, code: { family: 'JetBrains Mono', fallbacks: '"SF Mono", Monaco, Consolas, monospace', }, },- Outfit承担标题与正文,基准字号 14px、比例 1.25(即 h 系列按 1.25 的等比缩放向上递增),并为用户系统字体预留了完整 fallback 链;
- Sarina(手写体)只用于
text组件的type:display-1 / display-2 / display-3三个展示级尺寸,通过组件覆盖的fontFamily引入(含"Brush Script MT", "Snell Roundhand", cursive回退),README 说明其通过页级内联样式应用,专门留给 hero / 营销级大标题,正文与标题不使用它; - JetBrains Mono用于代码,fallback 到
"SF Mono", Monaco, Consolas。
源码级原理:调色板如何再生成
单锚点平滑渐变算法
generate-palettes.mjs 是调色板的生成器。它的核心思路是"单锚点"(single-anchor):每个色板只有一个源色(source hex),整套 21 步渐变通过CIELab → HCT色彩空间算法推导得到——这与主题预览条ThemePalettePreview使用的算法一致,从而保证"渲染的色带"与"消费的 token 值"严格 1:1。
关键实现细节:
hexToHct:把 hex 依次转换为 sRGB → linear RGB → XYZ(D65 白点)→ Lab,再从 Lab 中分离出 hue(色相角)、chroma(彩度)与 tone(明度 0–100);hctToHex:反向迭代求解,通过二分逼近保证颜色落在 sRGB 色域内(chroma < 0.5时直接退化为灰度),从而得到给定 tone 下的最纯色;tonalPalette(hue, chroma):对STEPS = [0,5,10,...,95,100]逐个 tone 生成颜色,并带有彩度增强逻辑——t < 50时按1 + (50 - t) / 40提高 chroma(低 tone 端需要更高彩度才能保持色相可见),上限为源色彩度的 1.8 倍。
SOURCES 选择策略与再生成流程
生成器把SOURCES映射表(generate-palettes.mjs)作为唯一输入:
const SOURCES = { blue: '#bdc5eb', cyan: '#8dd2d3', green: '#a5d29d', orange: '#f2bd81', pink: '#f0b3e8', purple: '#ddb9f6', red: '#f4b8ae', teal: '#94d3bb', yellow: '#e5d765', neutral: '#c1c6d5', accent: '#225BFF', error: '#ffb3a5', warning: '#f7be00', success: '#91D143', };选择源色时有一个精妙的约定:分类色以T80(浅色边框色)作为锚点,让中浅色音阶保持"诚实"(mid-light tone honest),使渐变向两端平滑展开;对于 T80 本身彩度过高、难以向两端展开的色相(如黄色),则改用略高的 tone 作为源。而语义色(error / warning / success)直接用 vivid 品牌色作锚,让色板在徽章填充色附近扎根。
再生成步骤(README 明确给出):
- 编辑
SOURCES映射中的源色 hex; - 运行生成脚本(仓库根目录下执行):
node packages/themes/butter/scripts/generate-palettes.mjs- 脚本会向 stdout 打印完整的
export const butterPalettes = {...}代码,将其粘贴回 butterTheme.ts 中替换原有butterPalettes定义即可。
脚本注释还提醒:T15 / T25 / T80 / T90 这四个"在用音阶"会与当前 token 值"接近但不一定完全相等",脚本打印新 T 值与旧 token 的差值(delta),方便确认色板漂移程度。
组件级定制与图标注册表
组件覆盖(components 配置)
defineTheme的components段允许主题在不改组件源码的前提下,按组件与变体精确覆盖样式。Butter 的覆盖策略可以从源码中归纳为几个清晰的模式:
- TopNav 强调品牌蓝:top-nav-heading 与 top-nav-item 覆盖 将标题与选中项设为完整品牌蓝
#225BFF(暗色模式为黄油黄#FDEE8C),未选中项用更浅的蓝#6E92FF;选中项刻意不设背景药丸,依靠字重与颜色制造强调; - 按钮(Button):不钉死圆角(保留 core 的
--_button-radius回退,保证独立按钮 8px、聊天输入框内可被覆盖成全圆角);variant:secondary用蓝色描边 + 蓝色文字(暗色模式切黄油黄),hover 添加#225BFF14半透明蓝底;variant:destructive使用粉彩红底#ffdad3+ 深红文字#550000; - 横幅(Banner)与字段状态(FieldStatus):在局部作用域内覆写
--color-*-muted等语义 token,使横幅头部渲染出与徽章一致的 vivid 填充色,且不会泄漏到全局; - 输入类组件:
text-input、text-area、number-input、date-input、time-input、selector、multi-selector、typeahead、tokenizer统一使用--spacing-2的垂直内边距与更柔和的边框,并把status:success / warning / error的语义色局部重映射为徽章同款 vivid 色,让状态图标与边框与横幅读感一致; - 圆角与阴影:
--radius-element: 8px(按钮、徽章、输入框)、--radius-container: 12px(卡片、横幅、弹层),--radius-none与--radius-full恒定为 0 与 9999px 不可被主题缩放;阴影统一使用暖中性色#1d1c11的透明色阶。
图标注册表
Butter 自带的butterIconRegistry(见 icons.tsx)把语义图标名映射到lucide-react的图标组件(close、check、success、error、warning、info、search、calendar、menu等 30 个),所有图标统一size: '1em'、aria-hidden,随主题打包而非随 Core 打包——这也是lucide-react出现在依赖而非 peer 依赖的原因。
构建产物与发布形态
package.json的build脚本展示了完整的产物流水线:
node ../../../scripts/clean-dist.mjs \ && astryx theme build src/butterTheme.ts -o dist/theme.css --icons-specifier ./icons.mjs \ && tsup \ && tsc --project tsconfig.build.json \ && node ../../../scripts/check-fully-specified.mjs即:先清理dist,再由 Astryx CLI 将src/butterTheme.ts编译为dist/theme.css(对应theme.css导出),随后tsup(配置见 tsup.config.ts,对source.ts与icons.tsx分别产出 CJS / ESM)与tsc生成类型声明,最后用check-fully-specified校验所有导出路径均已声明,确保发布包的导入路径完备。最终files字段发布dist与src两目录。
小结
@astryxdesign/theme-butter是一个完整的、可独立发布与消费的 Astryx 主题包:XDSTheme+theme.css一行挂载即可应用;21 步色调色板由 CIELab → HCT 算法从单一锚点平滑生成,T90 / T80 / T25 音阶约定统一了徽章、卡片、横幅的明暗角色映射;Sarina × Outfit × JetBrains Mono 组合定义了从展示级大标题到代码的完整字体阶梯;组件级覆盖与图标注册表则让主题能在不触碰组件源码的前提下精准定制品牌感知。若想进一步了解 Astryx 主题规范与架构约定,可继续阅读 主题规范索引 与 主题编译、主题令牌 等架构文档。
【免费下载链接】astryxAn open source design system that's fully customizable and agent ready项目地址: https://gitcode.com/GitHub_Trending/as/astryx
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考