i18n 搞定多语言,
KDF 搞定你的设计。
全都装进 JSON 里。
为服务端 Web 应用和 AI 辅助开发量身定制的 JSON 设计层。把布局、间距、排版、组件样式这些需要复用的决策全部集中到一个事实来源里。AI 智能体直接读文件,不用再跨文件、跨页面或者翻历史记录去瞎猜你的设计意图了。
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
靠这一个事实来源,就能让你的每个页面、组件还有和 AI 的对话内容保持绝对一致。
JSON 负责定义 · 代码负责渲染 · data-kdf 相互映射
设计规范在你的
组件库里慢慢走样。
当你的 class 类名全都硬编码在 .tsx 文件里时,每个页面的样式早晚会偏离初衷。人类开发者勉强还能应付一下,但要是换成 AI 智能体来写 UI,这套玩法就彻底崩了。
<section className="mx-auto max-w-6xl px-6 py-20"> <h1 className="text-5xl font-semibold tracking-tight"> // …and again, slightly different, on the next page
同一个按钮不知不觉变出了五种样子;页面和页面之间的间距怎么看怎么别扭。每次开启一个新的 AI 对话,它都得把你的设计规则从头再猜一遍。
- — AI 智能体会自己在那边瞎猜颜色、间距、排版和布局。
- — 每次你都得在聊天框里教它怎么改,改完还是不对。
- — 一有变动,你就得去各个组件文件里到处翻。
- — 稍微多聊几句,AI 就把你的设计初衷忘得一干二净。
→ 无休止的 "大点儿" · "再蓝点儿" · "往左靠靠" 循环微调
让设计变得清清楚楚。
KDF 在设计上干的活儿,就跟 i18n 在多语言上干的活儿一模一样:把那些可以复用的决策从组件里抽离出来,丢进 JSON 里。最后渲染出来的 UI 用的还是普通的 CSS,改变的只是“谁来管这些样式”。
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
组件库告诉你它是啥,
KDF 告诉你 它对应啥设计。.
组件库给你丢过来一个 Button 组件,而 KDF 告诉你,这玩意儿是 homepage.hero.cta-primary,它会被渲染成一个 Button,并且用的是这个 token 里的样式。它恰好补上了组件库经常缺失的那一环:元素和设计决策之间的映射关系。
六个符号,
一套语法。
KDF 里存了 class 类名、共享引用、区块顺序,还有 CSS 变量。但它绝对不会去碰你的业务逻辑、事件监听、数据请求、权限控制或者无障碍 (a11y) 功能。
每个用上 token 的元素都会带上一串对应的路径。DOM 节点直接就能追溯回 JSON —— 这对自动化扫描、写测试或者让 AI 来审查简直爽翻了。
把路径解析成 className 字符串。d.css() 会直接给你扔回来一个 CSS custom properties 对象。
指向 shared/ 目录下的高频复用 token。Refs 还能链式调用,或者加上额外的 class 来做扩展。
其实就是一个存着区块 keys 的数组。列出来的区块按顺序渲染;没列出来的,宿主应用会自动把它们藏起来。
主要是给 AI 智能体和宿主工具看的元数据 —— 告诉你这个 token 是被哪个组件渲染的,还顺带附上了变体和尺寸提示。
遇到那些没法用 class 表达的值,直接通过 d.css() 以行内样式变量的形式扔进去。
共享默认值,
页面按需覆盖。
设计 token 存在两个地方:可以随便复用的默认值放在 shared/ 里;而页面级别的配置只覆盖它确实需要改的那点东西。最后生成两个由你完全掌控的 CSS 文件,一个保首屏,一个用来兜底。
kdf/ shared/ button.json ← reusable defaults card.json color.json typography.json homepage.json ← page composition konde-server.css ← critical, first paint konde.css ← non-critical tweaks
像 @button.cta 这样的引用,解析的时候会先看页面的 shared/,再看父级的 shared/,最后看页面的 tokens。模板只覆盖自己要改的,剩下的原样继承过来。
设计都在服务端解析完了;浏览器拿到的全是干干净净的 class 字符串。关键 CSS 跟着首屏一起加载,剩下的慢慢来 —— 绝不给低配机器增加渲染负担。
应用加载时直接 import 进来,让设计变量和防闪烁 (no-FOUC) 的覆盖样式在第一帧就准备好 —— 页面绝对不会闪一下。
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
等框架和应用的 CSS 都加载完了再加载它,主要用来做微调、搞点实验性样式或者做个兜底 —— 这种细枝末节的东西,犯不上阻塞页面渲染。
/* konde.css */ [data-kdf="hero.title"] { letter-spacing: -0.02em; } [data-kdf="hero.wrapper"] { gap: 3rem; }
→ KDF 只会把它们建好一次,以后绝对不碰。插件会通过环境变量把路径暴露给你,你自己决定在应用里怎么 import;背地里绝对不搞什么偷偷注入那一套。
换个设计模板,
就像换语言包一样简单。
就像 i18n 切换语言一样,KDF 切换设计模板也是丝般顺滑。应用没变,组件没变,连代码都不用动 —— 把 KDF_DIR 指向另一个设计文件夹,整个站点的脸直接就换了。
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
在服务端解析好,
纯字符串往下传。
KDF 核心直接从硬盘里把 JSON 读出来,所以它理所当然地跑在服务端:不管你是 Next.js Server Components, Astro 渲染器, 还是 Hono 处理器。在服务端把 class 算明白,然后把纯字符串传给客户端组件。
import { getDesign, cn } from "@kondeio/kdf"; const d = getDesign("homepage"); <button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
→ 吐出解析好的 className 字符串
→ 吐出 CSS custom-properties 对象
把条件 class 拼起来,扔掉 falsy 的空值,顺便去个重 —— 默认没有任何语义负担。
上生产环境自动给你加缓存;本地开发的时候就看文件的修改时间 (mtime) 和大小来热更新。
它可以无缝坐在
你的整个技术栈上面。
样式层 —— 只存 CLASS 名,绝不硬塞 CSS
KDF 并不是个 CSS 引擎。只要你的样式系统认,Token 里存什么样奇葩的 class 字符串都行。要是你的框架有扫描源码文件这步操作,顺手把 JSON 的路径也给加上呗:@source "../kdf/**/*.json"。
运行时环境 —— 服务端 JAVASCRIPT
一键装好,
剩下的交给我们。
要是没有 kdf/ 文件夹,安装的时候会顺手给你生成一个基础模板。放心,绝对不会动你已经写好的代码。
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);