i18n이 번역을 담당한다면,
KDF는 디자인을 담당하죠.
둘 다 JSON에 살고요.
서버사이드 웹 앱과 에이전트가 짜주는 UI를 위한 JSON 기반 디자인 코디네이션 레이어입니다. 레이아웃, 간격, 타이포그래피, 컴포넌트 스타일링 등 반복되는 결정사항을 단 하나의 진실 공급원에 모아두세요. 에이전트가 이 파일 저 파일 뒤지거나 과거 세션에서 삽질할 필요 없이 이 JSON 하나만 쓱 읽어오면 됩니다.
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
단 하나의 진실 공급원이 모든 페이지, 컴포넌트, 에이전트 세션의 일관성을 꽉 잡아줍니다.
JSON이 정의하고 · 코드가 렌더링하며 · data-kdf 가 다시 연결해줍니다
여러분의 컴포넌트 안에서
디자인 파편화가 일어나고 있습니다.
클래스명이 오로지 .tsx 파일 안에만 갇혀 있으면, 페이지가 늘어날수록 디자인은 서서히 어긋나게 됩니다. 사람 혼자 짤 땐 괜찮지만, 에이전트가 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
같은 버튼인데도 알게 모르게 5가지 버전이 생겨납니다. 페이지마다 간격이 들쭉날쭉해지고요. 새 에이전트 세션을 켤 때마다 디자인 룰을 처음부터 다시 가르쳐야 하죠.
- — 에이전트가 컬러, 간격, 폰트, 레이아웃을 마음대로 지어냅니다.
- — 매번 유저가 채팅으로 그걸 하나하나 짚어주며 고쳐야 해요.
- — 수정 한 번 하려면 컴포넌트 파일들을 싹 다 뒤져야 하죠.
- — 세션을 새로 열면 기존에 잡아둔 디자인 의도가 날아갑니다.
→ 끝없는 "좀 더 크게" · "더 파랗게" · "왼쪽으로 옮겨" 삽질의 연속
디자인을 밖으로 끄집어내세요.
KDF는 i18n이 텍스트에 한 일을 디자인에 똑같이 적용한 겁니다. 반복되는 결정들을 컴포넌트 파일 밖으로 빼내 JSON으로 옮기죠. 화면에 그려지는 UI는 여전히 평범한 CSS를 쓰지만, 주도권(ownership)이 어디에 있는지가 달라지는 겁니다.
{ "hero": { "title": "text-5xl font-semibold tracking-tight" } }
const d = getDesign("homepage"); <h1 data-kdf="hero.title" className={d("hero.title")}>
라이브러리가 '무엇'인지 묻는다면,
KDF는 '어떤 것'.
디자인 라이브러리는 우리에게 컴포넌트를 던져주죠. 반면 KDF는 이 요소가 homepage.hero.cta-primary 이며, 버튼으로 그려지고 특정 토큰으로 스타일링된다는 걸 짚어줍니다. 라이브러리엔 쏙 빠져 있는 딱 한 가지, 즉 요소와 디자인 룰을 1:1로 매핑해주는 역할을 해요.
6개의 기호.
하나의 문법.
KDF는 클래스명, 공유 참조(ref), 섹션 순서, CSS 커스텀 속성을 보관합니다. 비즈니스 로직이나 이벤트 핸들러, 데이터 페칭, 권한, 접근성 같은 건 절대 건드리지 않아요.
토큰을 쓰는 모든 요소는 그에 맞는 경로를 꼬리표처럼 달고 다닙니다. DOM 노드에서 JSON까지 한 큐에 추적할 수 있어서 스캐너나 테스트, 에이전트가 코드 리뷰할 때 딱이죠.
경로를 던져주면 그에 맞는 className 문자열로 풀어줍니다. d.css()를 쓰면 CSS 커스텀 속성 객체를 뱉어주고요.
shared/ 폴더에 있는 재사용 가능한 토큰을 가리킵니다. 참조를 체이닝하거나 추가 클래스로 살을 붙일 수도 있어요.
섹션 키 배열입니다. 리스트에 적힌 순서대로 화면에 그려지고, 안 적힌 건 호스트 앱에서 깔끔하게 숨겨줍니다.
이 토큰을 렌더링할 컴포넌트가 뭔지, 어떤 variant나 사이즈가 쓰이는지 에이전트와 툴에게 슬쩍 알려주는 메타데이터입니다.
재사용 가능한 클래스로 딱 안 떨어지는 값들은 d.css()를 통해 인라인 스타일 변수로 먹여줍니다.
다 같이 쓰는 공유 셋업.
페이지별 오버라이드.
디자인 토큰은 딱 두 군데 삽니다. 재사용 가능한 기본값들은 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/ 로 올라갔다가 최종적으로 페이지 토큰을 적용합니다. 템플릿은 필요한 것만 쏙쏙 덮어쓰고 나머진 다 물려받는 구조예요.
디자인 세팅은 서버에서 다 끝납니다. 브라우저는 완성된 클래스 문자열만 쏙 받아가죠. 크리티컬 CSS는 첫 페인트 때 바로 꽂히고 나머지는 천천히 불러오니까 똥컴에서도 렌더링을 갉아먹지 않아요.
앱이 가장 먼저 불러오기 때문에 디자인 변수와 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는 이 파일들을 처음 한 번만 만들고 다신 건드리지 않아요. 플러그인이 환경변수로 경로를 뚫어주면 앱에서 알아서 임포트하는 식입니다. 제멋대로 코드를 쑤셔넣지 않아요.
언어를 바꾸듯
디자인을 휙휙 바꿔보세요.
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 서버 컴포넌트, Astro 렌더링, Hono 핸들러 같은 곳이요. 거기서 복잡한 클래스 조합을 다 끝내고 클라이언트 컴포넌트엔 그저 깔끔한 문자열 하나 툭 던져주는 식이죠.
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 커스텀 속성 객체
조건부 클래스를 하나로 합치고, falsy 값은 쳐내고, 중복은 알아서 빼줍니다. 기본적으론 의미론적(semantic) 간섭 없이 담백하게 동작해요.
프로덕션에선 빡세게 캐싱하고, 개발 환경에선 파일 수정 시간(mtime)과 사이즈를 보고 그때그때 갱신합니다.
여러분의 스택 위에
살포시 얹어 쓰세요.
스타일링 — CSS가 아니라 클래스명을 씁니다
KDF는 CSS 엔진이 아니에요. 여러분의 스타일링 시스템이 알아먹는 클래스 문자열이면 뭐든 토큰에 때려 넣을 수 있죠. 쓰시는 프레임워크가 소스 파일을 스캔하는 방식이라면 JSON도 같이 스캔하라고 @source "../kdf/**/*.json" 처럼 한 줄 쓱 넣어주기만 하면 끝입니다.
런타임 — 서버사이드 자바스크립트
설치는 딱 한 번.
나머진 init으로 알아서 세팅.
설치할 때 kdf/ 폴더가 없으면 알아서 기본 뼈대를 쫙 깔아줍니다. 이미 짜놓은 파일은 절대 안 덮어쓰니까 걱정 마시고요.
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);