i18n ดูแลเรื่องการแปลภาษา
KDF ดูแลเรื่องดีไซน์
ทั้งคู่อยู่ใน JSON
เลเยอร์ประสานงานดีไซน์แบบ JSON สำหรับเว็บแอปฝั่ง server และ UI ที่ทำงานร่วมกับ agent การตัดสินใจที่ทำซ้ำได้ ไม่ว่าจะเป็นเลย์เอาต์ ระยะห่าง ตัวอักษร สไตล์คอมโพเนนต์ ทั้งหมดอยู่ในแหล่งเดียวที่ agent อ่านได้ ไม่ต้องค้นหาใหม่ทุกครั้ง
{ "$layout": ["hero", "footer"], "hero": { "wrapper": "mx-auto max-w-6xl px-6 py-20", "title": "@typography.h1", "cta-primary": "@button.cta" } }
แหล่งข้อมูลเดียวทำให้ทุกหน้า ทุกคอมโพเนนต์ และทุก agent session สอดคล้องกัน
JSON กำหนด · โค้ดเรนเดอร์ · data-kdf แม็พกลับ
ดีไซน์ค่อยๆ เพี้ยนไป
ในคอมโพเนนต์ของคุณ
เวลา class name อยู่แค่ในไฟล์ .tsx แต่ละหน้าก็ค่อยๆ แตกต่างกันไปเรื่อยๆ สำหรับคนแก้คนเดียวมันพอไปได้ แต่พอ agent เริ่มแตะ 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
ปุ่มเดียวกันค่อยๆ แตกออกเป็นห้าแบบโดยไม่รู้ตัว spacing เปลี่ยนไปทีละหน้า agent session ใหม่ทุกครั้งต้องมาค้นหา design rules กันใหม่หมด
- — Agent เดาสี ระยะห่าง ตัวอักษร และเลย์เอาต์เอาเอง
- — ผู้ใช้ต้องแก้ผลลัพธ์ผ่านแชทบ่อยๆ ทุกครั้ง
- — แก้อะไรทีต้องค้นหาในไฟล์คอมโพเนนต์หลายไฟล์
- — เปิด session ใหม่ทีไร design intent หายทุกที
→ วนลูป "ใหญ่กว่า" · "น้ำเงินกว่า" · "เลื่อนซ้าย" ไม่จบไม่สิ้น
ทำให้ดีไซน์ชัดเจน
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")}>
Library บอกว่าอะไร
KDF บอกว่าตัวไหน.
Design library ให้คุณ Button แต่ KDF บอกว่านี่คือ homepage.hero.cta-primary เรนเดอร์เป็น Button ใช้สไตล์จาก token นี้ มันเพิ่มสิ่งที่ library ไม่ได้ทำ — การแม็พจาก element ไปยัง design decision
หกสัญลักษณ์
ไวยากรณ์เดียว
KDF เก็บ class name, shared reference, ลำดับ section, และ CSS custom properties ไม่เก็บ business logic, event handler, data fetching, สิทธิ์, หรือพฤติกรรม accessibility
ทุก element ที่ใช้ token จะมี path ที่ตรงกัน DOM node ชี้กลับไปที่ JSON ได้เลย สำหรับ scanner, test, และ agent review
แปลง path เป็น className string d.css() คืนค่า CSS custom properties object
ชี้ไปที่ reusable token ใน shared/ สามารถเชื่อมต่อและเพิ่ม class เพิ่มเติมได้
อาร์เรย์ของ section key section ที่มีอยู่จะเรนเดอร์ตามลำดับ ที่ขาดไปจะถูกซ่อนโดยแอปหลัก
เมทาดาต้าสำหรับ agent และเครื่องมือ — คอมโพเนนต์ไหนเรนเดอร์ token นี้ รวมถึง variant และ hint เรื่องขนาด
ค่าที่ไม่สามารถเขียนเป็น reusable class ได้ ใช้เป็น inline style variable ผ่าน d.css()
ค่าเริ่มต้นที่ใช้ร่วมกัน
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
Reference อย่าง @button.cta จะ resolve จาก shared/ ของหน้า, จากนั้น shared/ ของ parent, แล้วก็ page tokens เทมเพลต override แค่ส่วนที่ต้องการ ที่เหลือ inherit มาทั้งหมด
ดีไซน์ resolve บน server เบราว์เซอร์ได้รับ class string ที่พร้อมใช้ Critical CSS อยู่ใน first paint ส่วนที่เหลือโหลดทีหลัง ไม่โยนภาระ render ให้เครื่องสเปคต่ำ
ถูก import โดยแอป ทำให้ design variable และ override ป้องกัน FOUC มาถึงตั้งแต่ first paint เลย ก่อนที่อะไรจะกะพริบ
/* konde-server.css */ :root { --kdf-primary: #1F8F47; } [data-kdf="hero.slider"] { display: none; }
โหลดหลังจาก 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 ให้
สลับดีไซน์
เหมือนสลับภาษา
เหมือนที่ i18n สลับภาษา KDF ก็สลับ design template ได้ แอปเดิม คอมโพเนนต์เดิม โค้ดเดิม แค่ชี้ KDF_DIR ไปที่โฟลเดอร์ดีไซน์อื่น ลุคทั้งหมดก็เปลี่ยน
designs/ lander/ shared/ homepage.json newlander/ shared/ homepage.json
// next.config.ts withKDF({ dir: "./designs/lander" })(nextConfig);
Resolve บน server
ส่ง string ลงไป
KDF core อ่าน JSON จาก disk จึงทำงานฝั่ง server: Next.js Server Components, Astro renders, Hono handlers Resolve class ที่นั่น แล้วส่ง string ธรรมดาให้ client components
import { getDesign, cn } from "@kondeio/kdf"; const d = getDesign("homepage"); <button data-kdf="hero.cta" className={cn(d("hero.cta"), isActive)}>Start</button>
→ className string ที่ resolve แล้ว
→ CSS custom-properties object
รวม class แบบมีเงื่อนไข ตัดค่า falsy ออก dedupe — ไม่ยึดติด semantic
Production แคช dev revalidate ตาม mtime & size
มันอยู่เหนือ
stack ของคุณ
STYLING — เก็บ CLASS NAME ไม่ใช่ CSS
KDF ไม่ใช่ CSS engine Token เก็บ class string อะไรก็ได้ที่ styling system ของคุณเข้าใจ ถ้า framework ต้อง scan source file ให้ชี้ไปที่ JSON ด้วย: @source "../kdf/**/*.json"
RUNTIME — SERVER-SIDE JAVASCRIPT
ติดตั้งครั้งเดียว
Init จัดการที่เหลือให้
การติดตั้งจะสร้างโฟลเดอร์ kdf/ เริ่มต้นให้ด้วย ถ้ายังไม่มี ไฟล์ที่มีอยู่แล้วจะไม่ถูกเขียนทับ
import withKDF from "@kondeio/kdf/plugin"; export default withKDF({ dir: "./designs" })(nextConfig);