Konde Design Framework

i18n ดูแลเรื่องการแปลภาษา
KDF ดูแลเรื่องดีไซน์
ทั้งคู่อยู่ใน JSON

เลเยอร์ประสานงานดีไซน์แบบ JSON สำหรับเว็บแอปฝั่ง server และ UI ที่ทำงานร่วมกับ agent การตัดสินใจที่ทำซ้ำได้ ไม่ว่าจะเป็นเลย์เอาต์ ระยะห่าง ตัวอักษร สไตล์คอมโพเนนต์ ทั้งหมดอยู่ในแหล่งเดียวที่ agent อ่านได้ ไม่ต้องค้นหาใหม่ทุกครั้ง

kdf / homepage.json → เรนเดอร์แล้ว
kdf/homepage.json
{
  "$layout": ["hero", "footer"],
  "hero": {
    "wrapper": "mx-auto max-w-6xl px-6 py-20",
    "title":   "@typography.h1",
    "cta-primary": "@button.cta"
  }
}
data-kdf="hero.title"
สร้างและส่งมอบด้วย AI
data-kdf="hero.body"

แหล่งข้อมูลเดียวทำให้ทุกหน้า ทุกคอมโพเนนต์ และทุก agent session สอดคล้องกัน

data-kdf="hero.cta-primary"
เริ่มเลย →

JSON กำหนด · โค้ดเรนเดอร์ · data-kdf แม็พกลับ

License
MIT
Runtime
Node Filesystem
Dependencies
Zero Runtime
ทดสอบกับ
Next · Astro · Hono
01 — ปัญหา

ดีไซน์ค่อยๆ เพี้ยนไป
ในคอมโพเนนต์ของคุณ

เวลา class name อยู่แค่ในไฟล์ .tsx แต่ละหน้าก็ค่อยๆ แตกต่างกันไปเรื่อยๆ สำหรับคนแก้คนเดียวมันพอไปได้ แต่พอ agent เริ่มแตะ UI ปัญหาก็มาทันที

ไม่มี kdf · กระจายไปทั่วไฟล์
<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

ปุ่มเดียวกันค่อยๆ แตกออกเป็นห้าแบบโดยไม่รู้ตัว spacing เปลี่ยนไปทีละหน้า agent session ใหม่ทุกครั้งต้องมาค้นหา design rules กันใหม่หมด

ผลลัพธ์ที่ได้
  • Agent เดาสี ระยะห่าง ตัวอักษร และเลย์เอาต์เอาเอง
  • ผู้ใช้ต้องแก้ผลลัพธ์ผ่านแชทบ่อยๆ ทุกครั้ง
  • แก้อะไรทีต้องค้นหาในไฟล์คอมโพเนนต์หลายไฟล์
  • เปิด session ใหม่ทีไร design intent หายทุกที

→ วนลูป "ใหญ่กว่า" · "น้ำเงินกว่า" · "เลื่อนซ้าย" ไม่จบไม่สิ้น

02 — ทางออก

ทำให้ดีไซน์ชัดเจน

KDF ทำกับดีไซน์เหมือนที่ i18n ทำกับข้อความ — ย้ายการตัดสินใจที่ทำซ้ำได้ออกจากไฟล์คอมโพเนนต์ไปไว้ใน JSON ตัว UI ที่เรนเดอร์ออกมายังใช้ CSS ปกติ สิ่งที่เปลี่ยนคือใครเป็นเจ้าของ

1 — กำหนดไว้ใน json
{
  "hero": {
    "title": "text-5xl font-semibold tracking-tight"
  }
}
2 — เรนเดอร์ในโค้ด
const d = getDesign("homepage");

<h1 data-kdf="hero.title" className={d("hero.title")}>
JSON กำหนด
ไฟล์เดียวเป็นเจ้าของทิศทางดีไซน์ ผู้ใช้แก้ไขได้โดยตรงเมื่อต้องการควบคุมอย่างละเอียด
โค้ดเรนเดอร์
คอมโพเนนต์อ่าน token แล้วเรนเดอร์ดีไซน์ที่อนุมัติแล้วด้วย CSS ปกติ ไม่มีอะไรซับซ้อนข้างใต้
Agent สร้าง UI
Agent สร้าง UI จาก JSON แทนที่จะเดาเอง ไม่มีการแต่ง spacing สี ตัวอักษร หรือลำดับ section ขึ้นมาเอง
ผู้ใช้ปรับ JSON
แก้ที่ต้นทางครั้งเดียว แทนที่จะบอกเรื่องเดิมซ้ำๆ ในแชท session แล้ว session เล่า
03 — ไม่ใช่ component library

Library บอกว่าอะไร
KDF บอกว่าตัวไหน.

Design library ให้คุณ Button แต่ KDF บอกว่านี่คือ homepage.hero.cta-primary เรนเดอร์เป็น Button ใช้สไตล์จาก token นี้ มันเพิ่มสิ่งที่ library ไม่ได้ทำ — การแม็พจาก element ไปยัง design decision

 Design libraryKDF
บอกอะไร"นี่คือ Button""นี่คือ hero.cta-primary ใน homepage"
การแม็พคอมโพเนนต์ทั่วไป มีหลาย override ที่เป็นไปได้หนึ่ง element แม็พกับหนึ่ง design key
ตรวจสอบได้ไม่มีแผนที่ชัดเจนจาก element ไปยัง decisiondata-kdf ชี้ทุก DOM node ไปยัง JSON path ของมัน
อยู่เหนือ shadcn · Bootstrap · Chakra · Tailwind · CSS ธรรมดา · ระบบของคุณเอง — KDF ไม่ได้มาแทนที่อะไรเลย
04 — คำศัพท์

หกสัญลักษณ์
ไวยากรณ์เดียว

KDF เก็บ class name, shared reference, ลำดับ section, และ CSS custom properties ไม่เก็บ business logic, event handler, data fetching, สิทธิ์, หรือพฤติกรรม accessibility

data-kdf
แผนที่

ทุก element ที่ใช้ token จะมี path ที่ตรงกัน DOM node ชี้กลับไปที่ JSON ได้เลย สำหรับ scanner, test, และ agent review

data-kdf="hero.title"
d(path)
ตัวเข้าถึง

แปลง path เป็น className string d.css() คืนค่า CSS custom properties object

className={d("hero.title")}
@
Shared reference

ชี้ไปที่ reusable token ใน shared/ สามารถเชื่อมต่อและเพิ่ม class เพิ่มเติมได้

"@button.cta" shadow-xl
$layout
ลำดับและการแสดงผล

อาร์เรย์ของ section key section ที่มีอยู่จะเรนเดอร์ตามลำดับ ที่ขาดไปจะถูกซ่อนโดยแอปหลัก

["hero", "features", "footer"]
$
ตัวตนของคอมโพเนนต์

เมทาดาต้าสำหรับ agent และเครื่องมือ — คอมโพเนนต์ไหนเรนเดอร์ token นี้ รวมถึง variant และ hint เรื่องขนาด

"$": "Button"
css
Custom properties

ค่าที่ไม่สามารถเขียนเป็น reusable class ได้ ใช้เป็น inline style variable ผ่าน d.css()

{ "--kdf-accent": "#4F46E5" }
05 — สถาปัตยกรรม

ค่าเริ่มต้นที่ใช้ร่วมกัน
Override ระดับหน้า

Design token อยู่สองที่: ค่าเริ่มต้นที่ใช้ซ้ำได้ใน shared/ และ composition ของแต่ละหน้าที่ override เฉพาะที่จำเป็น ไฟล์ CSS สองไฟล์ที่คุณเป็นเจ้าของ ครอบคลุม first paint และทางออกฉุกเฉิน

โครงสร้างโปรเจกต์
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
Cascade หลายระดับ

Reference อย่าง @button.cta จะ resolve จาก shared/ ของหน้า, จากนั้น shared/ ของ parent, แล้วก็ page tokens เทมเพลต override แค่ส่วนที่ต้องการ ที่เหลือ inherit มาทั้งหมด

เบาตั้งแต่ต้น

ดีไซน์ resolve บน server เบราว์เซอร์ได้รับ class string ที่พร้อมใช้ Critical CSS อยู่ใน first paint ส่วนที่เหลือโหลดทีหลัง ไม่โยนภาระ render ให้เครื่องสเปคต่ำ

ไฟล์ CSS สองไฟล์ · สองจังหวะโหลด
konde-server.css
critical · first paint

ถูก import โดยแอป ทำให้ design variable และ override ป้องกัน FOUC มาถึงตั้งแต่ first paint เลย ก่อนที่อะไรจะกะพริบ

/* konde-server.css */
:root { --kdf-primary: #1F8F47; }
[data-kdf="hero.slider"] { display: none; }
konde.css
non-critical · หลัง app css

โหลดหลังจาก CSS ของ framework และแอป สำหรับปรับแต่ง ทดลอง และทางออกฉุกเฉิน — fine-tuning ที่ไม่จำเป็นต้อง block paint

/* konde.css */
[data-kdf="hero.title"] { letter-spacing: -0.02em; }
[data-kdf="hero.wrapper"] { gap: 3rem; }

→ KDF สร้างทั้งสองไฟล์ครั้งเดียวและไม่เขียนทับ plugin เปิด path ผ่าน env แอปของคุณต่อสาย import เอง ไม่มีอะไรถูก inject ให้

06 — หลายเทมเพลต

สลับดีไซน์
เหมือนสลับภาษา

เหมือนที่ i18n สลับภาษา KDF ก็สลับ design template ได้ แอปเดิม คอมโพเนนต์เดิม โค้ดเดิม แค่ชี้ KDF_DIR ไปที่โฟลเดอร์ดีไซน์อื่น ลุคทั้งหมดก็เปลี่ยน

designs/ — สองเทมเพลต แอปเดียว
designs/
  lander/
    shared/
    homepage.json
  newlander/
    shared/
    homepage.json
// next.config.ts
withKDF({ dir: "./designs/lander" })(nextConfig);
$layout เรียงหรือซ่อน section ได้โดยไม่ต้องแตะคอมโพเนนต์
@button เปลี่ยน CTA ทั้งหมดทีเดียวผ่าน shared token
KDF_DIR สลับ design template ทั้งชุดเป็นการตัดสินใจที่ชัดเจนของ host
07 — Runtime API

Resolve บน server
ส่ง string ลงไป

KDF core อ่าน JSON จาก disk จึงทำงานฝั่ง server: Next.js Server Components, Astro renders, Hono handlers Resolve class ที่นั่น แล้วส่ง string ธรรมดาให้ client components

server component
import { getDesign, cn } from "@kondeio/kdf";

const d = getDesign("homepage");

<button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
d("hero.title")

→ className string ที่ resolve แล้ว

d.css("hero.title")

→ CSS custom-properties object

cn · cx · dedupeClasses

รวม class แบบมีเงื่อนไข ตัดค่า falsy ออก dedupe — ไม่ยึดติด semantic

cache: auto · always · none

Production แคช dev revalidate ตาม mtime & size

08 — ออกแบบมาให้เข้ากันได้

มันอยู่เหนือ
stack ของคุณ

STYLING — เก็บ CLASS NAME ไม่ใช่ CSS

TailwindshadcnBootstrapChakraCSS ModulesPlain CSSYour own system

KDF ไม่ใช่ CSS engine Token เก็บ class string อะไรก็ได้ที่ styling system ของคุณเข้าใจ ถ้า framework ต้อง scan source file ให้ชี้ไปที่ JSON ด้วย: @source "../kdf/**/*.json"

RUNTIME — SERVER-SIDE JAVASCRIPT

Next.js ทดสอบแล้ว · plugin
Astro ทดสอบแล้ว
Hono ทดสอบแล้ว
เริ่มต้นใช้งาน

ติดตั้งครั้งเดียว
Init จัดการที่เหลือให้

การติดตั้งจะสร้างโฟลเดอร์ kdf/ เริ่มต้นให้ด้วย ถ้ายังไม่มี ไฟล์ที่มีอยู่แล้วจะไม่ถูกเขียนทับ

$npm install @kondeio/kdf
$pnpm add @kondeio/kdf
$bun add @kondeio/kdf
$npm exec -- kdf init # scaffold แบบ manual
next.config.ts
import withKDF from "@kondeio/kdf/plugin";

export default withKDF({ dir: "./designs" })(nextConfig);