डिज़ाइन सिस्टम और कस्टमाइज़ेशन
एक शब्दावली, कई डिज़ाइन सिस्टम। कोई डायल बदलें, कोई पैलेट घोषित करें, किसी टोकन को दूसरी जगह मोड़ें — और हर प्लैटफ़ॉर्म एक ही कमिट में साथ चलता है।
Tanrei इस तरह बना है कि वह किसी भी डिज़ाइन सिस्टम को दोबारा बना सके — लगभग नहीं, बिलकुल ठीक — और फिर भी उसकी अपनी शब्दावली छोटी रहे। दो नियम इसे संभव बनाते हैं: डिज़ाइन सिस्टम सबसे पहले मानों में अलग होते हैं, और जो बात मान से नहीं कही जा सकती, उसे लेयर जोड़ती है।
Tanrei की कोर शब्दावली में वह हर अवस्था है जो एक डिज़ाइन सिस्टम एक प्रॉडक्ट के भीतर ले सकता है। इससे हर प्रस्तावित टोकन के लिए एक कसौटी मिलती है — “एक प्रॉडक्ट” कसौटी:
- वह टोकन है, अगर किसी एक प्रॉडक्ट को वह भेद चाहिए हो सकता है, अर्थ के कारण या जगह के कारण।
focus-ring,primaryसे अलग है, क्योंकि कोई प्रॉडक्ट गहरा ब्रैंड रंग और हल्की फ़ोकस रिंग चाह सकता है। डिफ़ॉल्ट सिस्टम इन्हें आपस में जुड़े मान देता है, यह संयोग है, इन्हें मिला देने का कारण नहीं। Button के साइज़ इसलिए हैं कि एक ही प्रॉडक्ट कई साइज़ इस्तेमाल करता है। - वह टोकन नहीं है, अगर वह सिर्फ़ किसी एक डिज़ाइन सिस्टम में, या किसी एक असामान्य प्रॉडक्ट में है। Material Design 3 का
tertiaryउस प्रीसेट में घोषित पैलेट है जो उसे दोबारा बनाता है, और उसकेprimary-fixedरोल उसी प्रीसेट के विस्तार हैं — ऐसी जगहें नहीं जिन्हें हर कोई ढोए। किसी एक अनोखे प्रॉडक्ट के लिए बटन के बीस साइज़ भी कोर शब्दावली नहीं हैं; वह प्रॉडक्ट उन्हें अपनी लेयर में जोड़ता है।
अगर इसके बाद भी किसी डिज़ाइन सिस्टम की कोई ख़ासियत दोबारा नहीं बन पाती — कोई बैकड्रॉप मटीरियल, टेक्स्ट साइज़ की उसकी अपनी टेबल — तो वह Tanrei की कमी है, जो मिमिक्री-गैप रजिस्ट्री में दर्ज होती है (रिपॉज़िटरी में docs/governance/mimicry-gaps.json)।
डिज़ाइन सिस्टम डिफ़ॉल्ट रूप से ठीक लगना चाहिए, और जब आप एक चीज़ बदलें तो आपके साथ चलना चाहिए। हर चीज़ के नीचे आठ संख्यात्मक डायल हैं:
| डायल | डिफ़ॉल्ट | क्या बदलता है |
|---|---|---|
dial.type.base |
16px | टेक्स्ट का हर साइज़ |
dial.type.contrast |
1 | हेडिंग बॉडी टेक्स्ट से कितनी अलग दिखती हैं |
dial.space.unit |
8px | हर दूरी |
dial.size.unit |
4px | कंट्रोल की ऊँचाई, आइकन के साइज़, हिट टार्गेट |
dial.density |
1 | कंट्रोल और पंक्तियों की ऊँचाई, और उनकी सामग्री के आसपास की जगह: 1 से कम पर पास-पास, 1 से ज़्यादा पर खुला-खुला |
dial.shape.unit |
2px | हर कोना |
dial.stroke.unit |
1px | बॉर्डर, रिंग, फ़ोकस इंडिकेटर |
dial.motion.unit |
50ms | हर अवधि |
हर टोकन तीन में से किसी एक प्रकार का होता है:
- व्युत्पन्न — एक छोटा नियम, आम तौर पर किसी डायल पर एक गुणांक:
displayहैtype.base × 3,space175हैspace.unit × 1.75। असली टाइप रैंप ज्यामितीय नहीं होते, इसलिए हर टोकन का अपना गुणांक है; - स्थिर — बताए गए कारण के साथ एक लिटरल, जो डायल से मुक्त है (
corner.full, कोई ईज़िंग कर्व, क़ानूनन तय फ़ुटनोट साइज़); - एलियास — एक रेफ़रेंस जिसे दूसरी जगह मोड़ा जा सकता है (
button.container.gap→space100)।
वेब पर डायल लाइव भी काम करते हैं: व्युत्पन्न टोकन calc() एक्सप्रेशन के रूप में निकलते हैं, इसलिए किसी भी एलिमेंट पर --tanrei-dial-type-base सेट करने से उसके भीतर सब कुछ नए सिरे से स्केल हो जाता है। एक टेस्ट हर व्युत्पन्न टोकन को असली ब्राउज़र में कई डायल सेटिंग पर निकालकर देखता है और माँगता है कि वह बिल्ड के नतीजे के बराबर हो।
डिज़ाइन सिस्टम एक छोटी JSON फ़ाइल है जो किसी दूसरे सिस्टम का विस्तार करती है। ज़्यादातर वह मान बदलती है; जहाँ ज़रूरी हो, वहाँ वह शब्दावली में जोड़ती है।
{
"id": "acme",
"extends": "tanrei",
"palettes": {
"brand": { "description": "Acme का लाल रंग ब्रैंड दिशानिर्देशों से तय है।", "source": { "seed": "#e60012" }, "roles": "intent" },
"correct": { "description": "क्विज़ सही जवाबों को चिह्नित करता है — यह न success है, न primary।", "source": { "seed": "#0f766e" }, "roles": "intent" }
},
"tokens": {
"tanrei.dial.type.base": { "$value": { "value": 17, "unit": "px" }, "reason": "हमारे पाठक हाथ भर की दूरी से पढ़ते हैं।" },
"tanrei.comp.button.container.padding-inline-start.medium": { "scale": 2 },
"tanrei.comp.button.container.gap.medium": { "$value": "{tanrei.sys.space.space50}" },
"tanrei.sys.typescale.label-small": { "$value": { "fontSize": { "value": 11, "unit": "px" } }, "reason": "क़ानूनी फ़ुटनोट का साइज़ अनुबंध से तय है।" }
}
}| आप चाहते हैं | आप लिखते हैं |
|---|---|
| सब कुछ थोड़ा बड़ा | एक डायल सेट करें |
| बटन की पैडिंग डिफ़ॉल्ट से दोगुनी — और फिर भी स्पेसिंग डायल के साथ चलती हुई | "scale": 2 |
| यह टोकन कोई दूसरा स्टेप इस्तेमाल करे | एलियास को दूसरी जगह मोड़ें |
| डायल कुछ भी करें, यह एक मान अपनी जगह रहे | $value को एक reason के साथ पिन करें |
ब्रैंड या डोमेन का रंग, अपने on- और -container रोल के साथ, कंट्रास्ट-जाँचा हुआ |
"roles": "intent" के साथ पैलेट घोषित करें |
चूँकि हर प्लैटफ़ॉर्म का कोड उसी एक रिज़ॉल्व किए गए सिस्टम से जनरेट होता है, इसलिए एक पुल रिक्वेस्ट वेब, SwiftUI, Compose, Flutter और React Native को एक साथ बदलती है।
मान हमेशा काफ़ी नहीं होते। किसी रेफ़रेंस सिस्टम में बटन के ऐसे साइज़ हैं जो कोर में नहीं हैं; आपके प्रॉडक्ट का अपना एक रेटिंग कंपोनेंट है। इसलिए लेयर शब्दावली का विस्तार भी कर सकती है — vocabulary के अंतर्गत, हमेशा एक rationale के साथ, और सिर्फ़ जोड़कर:
"vocabulary": {
"tanrei.sys.space.space1200": { "$type": "dimension", "rationale": "हीरो सेक्शन को 96px का रिदम स्टेप चाहिए।",
"derive": { "fn": "mul", "of": "{tanrei.dial.space.unit}", "by": 12 } },
"tanrei.comp.button.size.3x": { "from": "large", "scale": 1.5, "rationale": "लैंडिंग स्क्रीन पर हीरो कॉल-टू-ऐक्शन।" },
"tanrei.comp.button.variant.danger": { "from": "filled", "rationale": "विनाशकारी क्रिया की पुष्टि यहाँ एक अलग एम्फ़ेसिस है।" },
"acme.comp.rating.star.size": { "$type": "dimension", "rationale": "रेटिंग कंपोनेंट का तारा।",
"derive": { "fn": "mul", "of": "{tanrei.dial.size.unit}", "by": 5 } }
}| आप जोड़ते हैं | क्या होता है |
|---|---|
किसी सीरीज़ में एक स्टेप — स्पेसिंग का स्टेप, कोना, टेक्स्ट रोल, या ऐसा कलर रोल जिसके साथ उस पर बनने वाला रोल (onRole) भी हो |
वह अपने पड़ोसियों के बग़ल में बैठता है, उसी डायल के साथ चलता है, और कोर जोड़ी की तरह कंट्रास्ट के लिए जाँचा जाता है |
| कंपोनेंट के किसी अक्ष पर एक मान — Button का साइज़ या वेरिएंट | एक पंक्ति काफ़ी है। साइज़ उस अक्ष के हर सदस्य (ऊँचाई, पैडिंग, लेबल स्टाइल, आइकन) को किसी दूसरे साइज़ से क्लोन करके स्केल करता है, और डायल के साथ चलता रहता है। वेरिएंट अपने सामान्य अवस्था के रंग क्लोन करता है; उसके होवर, फ़ोकस, दबाए हुए और अक्षम स्टेट के टोकन के मान सिस्टम के पैटर्न नियम आपके लिए तय कर देते हैं |
आपके अपने टोकन, आपकी लेयर के नेमस्पेस में (acme.…) |
आपके अपने कंपोनेंट के लिए। वे किसी भी tanrei.* टोकन का रेफ़रेंस ले सकते हैं, डायल और स्कीम के साथ चलते हैं, और वेब पर --acme-… और बाक़ी हर प्लैटफ़ॉर्म पर एक टाइप किया हुआ ऑब्जेक्ट बन जाते हैं |
vocabulary कहती है कि कोई चीज़ मौजूद है; tokens और rules उसे मान देते हैं, ठीक कोर टोकन की तरह — इसलिए चाइल्ड लेयर किसी विस्तार को किसी भी दूसरी चीज़ की तरह बदल सकती है। विस्तार इनहेरिट होते हैं, कोर से कभी कुछ हटाते या उसका टाइप नहीं बदलते, और इंटरैक्शन स्टेट नहीं जोड़ सकते (वे प्लैटफ़ॉर्म के हैं)। हर जनरेट किया गया बंडल इन्हें इस ब्योरे के साथ सूचीबद्ध करता है कि इन्हें किसने घोषित किया और क्यों।
आप जो जोड़ते हैं, कंपोनेंट उसे स्वीकार करते हैं। <tanrei-button size="3x" variant="danger"> वेब पर काम करता है, और नेटिव पैकेज वही कुंजियाँ लेते हैं; जो मान सक्रिय डिज़ाइन सिस्टम में नहीं है, वह डिफ़ॉल्ट के रूप में रेंडर होता है। जो सिस्टम कुछ नहीं जोड़ता, वह कोई क़ीमत नहीं चुकाता: उसके जनरेट किए गए कोड में विस्तारों का ज़िक्र तक नहीं होता।
इसी तरह दो आदर्श एक साथ टिके रहते हैं: Tanrei की अपनी शब्दावली छोटी और सीधे-सादे नामों वाली रहती है, और किसी भी डिज़ाइन सिस्टम से ठीक-ठीक मेल बिठाया जा सकता है — क्योंकि किसी और की ख़ातिर कोर में कुछ जोड़ना नहीं पड़ता।
कंपोनेंट होवर या दबाए हुए स्टेट का रूप कभी ख़ुद नहीं निकालते। हर स्टेट के अपने टोकन हैं (button.filled.hovered.container.color, …), और सिस्टम के पैटर्न नियम उनके मान तय करते हैं:
{ "match": "tanrei.comp.*.*.hovered.container.color",
"derive": { "fn": "mix", "base": "{tanrei.comp.$1.$2.container.color}", "with": "{tanrei.comp.$1.$2.label.color}", "amount": "{tanrei.sys.state.hover-state-layer-opacity}" } }यही Tanrei की स्टेट लेयर है। जिस सिस्टम में हर स्टेट के रंग स्पष्ट रूप से दिए हैं, वह इसकी जगह एलियास लिखता है; जिसमें होवर नहीं है, वह उस स्टेट को उसके सामान्य अवस्था के मान का एलियास बना देता है; जो दबाने पर धुँधला करता है, वह pressed.opacity सेट करता है। शब्दावली वही, मान अलग।
कुछ अंतर मात्रा के होते ही नहीं: दबाने का जवाब रिपल से या कंट्रोल को धुँधला करके, कीबोर्ड फ़ोकस रिंग के रूप में या चमक के रूप में। ये sys.behavior के अंतर्गत दो टोकन हैं (pressed-feedback, focus-style), जिनमें हर एक के पास नामों की एक छोटी, बंद सूची है, और लेयर किसी भी दूसरे मान की तरह इनमें से एक चुनती है। कोना कैसे मुड़ता है, यह चुनाव नहीं, मात्रा है: शेप पेज पर sys.shape.corner-smoothing। इनका वर्णन व्यवहार पेज पर है। आइकन सेट और टाइपफ़ेस भी लेयर बदल सकती है: देखें आइकन और टाइपोग्राफ़ी।
वही <tanrei-button>, वही मार्कअप। m3-like और cupertino इसलिए हैं कि यह व्यवस्था उलटे स्वभाव वाले दो सिस्टमों पर साबित हो, और इसलिए भी कि वे आपकी अपनी लेयर के शुरुआती बिंदु बनें।
सटीकता मापी जाती है, उसका दावा नहीं किया जाता। m3-like के साथ material-web (Apache-2.0) के प्रकाशित टोकन से एक फ़िडेलिटी मैप है: रेफ़रेंस का हर कलर रोल, हर टेक्स्ट स्टाइल और Button का हर टोकन या तो बराबर होना चाहिए, या किसी दूसरे टोकन से कवर होना चाहिए, या उस मिमिक्री गैप के साथ सूचीबद्ध होना चाहिए जो उसे समझाता है। यह संख्या नीचे प्रीसेट के साथ दिखाई गई है — जो टोकन किसी दूसरे टोकन से कवर नहीं हैं, उनमें से कितने बराबर हैं — और tokens/generated/<id>/fidelity.json से पढ़ी जाती है। इसे “-like” ट्रेडमार्क के कारणों से कहा जाता है — इसलिए नहीं कि यह लगभग वैसा है।
tanrei Tanrei
- घोषित पैलेट
accent- बदले गए मान
- 152
- पैटर्न नियम
- 132
- WCAG
- हर स्कीम में हर इनवेरिएंट पूरा करता है। उल्लंघन होने पर बिल्ड विफल हो जाता है।
The default design system. Near-monochrome surfaces, a monochrome primary and one accent. It takes its values from core and leaves out the components and variants it does not draw.
cupertino Cupertino (Apple HIG-inspired)
- किसका विस्तार
core- घोषित पैलेट
- कोई नहीं
- बदले गए मान
- 581
- पैटर्न नियम
- 15
- शब्दावली के विस्तार
- 3
- फ़िडेलिटी (मापी गई)
- मापा नहीं गया — रेफ़रेंस मशीन से पढ़े जा सकने वाले टोकन प्रकाशित नहीं करता
- WCAG
- 113 कंट्रास्ट माप Tanrei के थ्रेशोल्ड से नीचे (सिर्फ़ स्टैंडर्ड कंट्रास्ट पर)। सिर्फ़ जानकारी: नक़ल करने वाले प्रीसेट पर Tanrei के सुलभता मानदंड किसी भी कंट्रास्ट स्कीम में लागू नहीं होते।
An independent approximation of the look of Apple's platforms, expressed purely as values: a saturated system tint, pure white and black canvases, gray fills with tinted labels, rounded rectangles, no hover state and a dimmed pressed state.
Tanrei is not affiliated with, endorsed by, or sponsored by Apple Inc. Apple is a trademark of Apple Inc. The values here are Tanrei's own approximations, not a transcription of Apple's documentation, and no Apple font or symbol is bundled: the system font is referenced by name only.
m3-expressive-like M3 Expressive-like (Material 3 Expressive-inspired)
- किसका विस्तार
m3-like- घोषित पैलेट
- कोई नहीं
- बदले गए मान
- 53
- पैटर्न नियम
- 0
- शब्दावली के विस्तार
- 2
- फ़िडेलिटी (मापी गई)
- 35 / 55 रेफ़रेंस टोकन बराबर · 0 अलग · 20 बिना मैपिंग के, दर्ज किए गए अंतर के साथ — androidx.compose.material3 button size tokensv0_11_0 (Apache-2.0)
- WCAG
- हर स्कीम में हर इनवेरिएंट पूरा करता है। सिर्फ़ जानकारी: नक़ल करने वाले प्रीसेट पर Tanrei के सुलभता मानदंड किसी भी कंट्रास्ट स्कीम में लागू नहीं होते।
m3-like with the five button sizes of Material 3 Expressive — extra small to extra large, each with its own paddings, icon size, icon-to-label gap and outline width. Colors, type, shape and states are m3-like's.
Tanrei is not affiliated with, endorsed by, or sponsored by Google. "Material Design" is Google's; this preset is an independent reproduction of published, Apache-2.0 licensed token values.
m3-like M3-like (Material 3-inspired)
- किसका विस्तार
core- घोषित पैलेट
tertiary- बदले गए मान
- 711
- पैटर्न नियम
- 19
- शब्दावली के विस्तार
- 18
- फ़िडेलिटी (मापी गई)
- 273 / 274 रेफ़रेंस टोकन बराबर · 0 अलग · 1 बिना मैपिंग के, दर्ज किए गए अंतर के साथ — material-webv0_192 (Apache-2.0)
- WCAG
- हर स्कीम में हर इनवेरिएंट पूरा करता है। सिर्फ़ जानकारी: नक़ल करने वाले प्रीसेट पर Tanrei के सुलभता मानदंड किसी भी कंट्रास्ट स्कीम में लागू नहीं होते।
An independent approximation of Material Design 3's baseline look, expressed purely as values over Tanrei's vocabulary: a chromatic primary, tonal surfaces, pill buttons, shadow elevation without a ring.
Tanrei is not affiliated with, endorsed by, or sponsored by Google. "Material Design" is Google's; this preset is an independent approximation derived from publicly available, Apache-2.0 licensed design tokens.
वेब पर प्रीसेट एक अतिरिक्त स्टाइलशीट है, जो एक ऐट्रिब्यूट तक सीमित रहती है, इसलिए सिस्टम अगल-बग़ल भी रह सकते हैं। प्रीसेट की एंट्री उसके सारे कॉम्पोनेंट रजिस्टर करती है, उनमें वे भी जो डिफ़ॉल्ट सिस्टम में नहीं हैं (@tanrei/web सिर्फ़ डिफ़ॉल्ट सिस्टम के कॉम्पोनेंट रजिस्टर करता है):
import '@tanrei/web/tokens.css';
import '@tanrei/web/systems/cupertino.css';
import '@tanrei/web/cupertino'; // cupertino के कॉम्पोनेंट<body data-tanrei-system="cupertino">जो बात अभी न मान कह सकते हैं, न प्रकार के चुनाव — बैकड्रॉप मटीरियल, स्टाइल के तौर पर अपरकेस लेबल — वह docs/governance/mimicry-gaps.json में Tanrei की कमी के रूप में दर्ज है, छिपाई नहीं गई।
कोई सिस्टम पूरा कॉम्पोनेंट छोड़ सकता है, या किसी कॉम्पोनेंट के variant का एक मान: डिफ़ॉल्ट सिस्टम में सेगमेंटेड बटन नहीं है, और filled या outlined टेक्स्ट फ़ील्ड भी नहीं। लेयर यह बात components में लिखती है, कारण के साथ और यह भी कि उसकी जगह क्या इस्तेमाल होता है:
"components": {
"omit": { "carousel": { "reason": "Acme shows one thing at a time.", "insteadUse": ["list"] } },
"variants": { "tabs": { "omit": ["tonal"] } }
}जो छोड़ा गया है, वह फिर भी दिखता है और काम करता है। डेवलपमेंट बिल्ड में, उसे इस्तेमाल करने वाला हर एलिमेंट कंसोल में एक बार चेतावनी देता है, जिसमें आपके सिस्टम का नाम और उसकी जगह इस्तेमाल होने वाली चीज़ होती है। चेतावनी उसी कॉम्पोनेंट का नाम लेती है जो आपने लिखा: <tanrei-text-field variant="outlined"> की रिपोर्ट टेक्स्ट फ़ील्ड के outlined के रूप में होती है, उस टेक्स्ट इनपुट के रूप में नहीं जिसे वह अंदर बनाता है। किसी दूसरे सिस्टम की लेयर में रहने वाले कॉम्पोनेंट की, जैसे m3-like का FAB मेन्यू, रिपोर्ट भी इसी तरह होती है, उस लेयर के नाम के साथ जिसमें वह रहता है।
इस पर अपने टेस्ट फ़ेल करने के लिए, इसकी रिपोर्ट एरर के रूप में करवाएँ, और पूछें कि क्या इस्तेमाल हुआ:
import { setAvailabilityMode, unavailableUses } from '@tanrei/web';
setAvailabilityMode('error'); // अपने टेस्ट सेटअप में, कुछ भी रेंडर होने से पहले
test('प्रॉडक्ट वही इस्तेमाल करता है जो उसके सिस्टम में है', async () => {
// …प्रॉडक्ट की स्क्रीन रेंडर करें…
expect(unavailableUses()).toEqual([]);
});unavailableUses() दोनों में से किसी भी मोड में हर इस्तेमाल को एक बार, वर्णक्रम में सूचीबद्ध करता है (segmented-button, text-field:outlined)। प्रोडक्शन बिल्ड कुछ नहीं जाँचता, इसलिए वहाँ सूची खाली रहती है। @tanrei/web/availability में यही दो फ़ंक्शन हैं, बिना कोई एलिमेंट रजिस्टर किए।
सिस्टम को बिल्ड करने पर एक स्वयंपूर्ण DTCG 2025.10 बंडल बनता है — सादी, पूरे मानों वाली टोकन फ़ाइलें और एक मानक रिज़ॉल्वर — इसलिए डिज़ाइन टोकन पढ़ने वाला कोई भी टूल इसे Tanrei के बिना इस्तेमाल कर सकता है। जिन लेयर फ़ाइलों से यह बना, वे बंडल के भीतर साथ चलती हैं, इसलिए Tanrei (या कोई AI एजेंट) इसे दोबारा बना या बदल सकता है।
सुलभता
कंट्रास्ट के थ्रेशोल्ड कॉन्स्टेंट हैं, जिन्हें कोई नहीं बदल सकता। डिफ़ॉल्ट सिस्टम में उल्लंघन होने पर बिल्ड विफल हो जाता है। प्रॉडक्ट की लेयर में उल्लंघन एक चेतावनी होता है — जो बिल्ड के समय छपती है और जनरेट की गई फ़ाइलों में लिखी जाती है, कभी चुपचाप नहीं गुज़रती। किसी दूसरे सिस्टम की नक़ल करने वाले प्रीसेट को इसके बजाय उस सिस्टम के प्रति फ़िडेलिटी पर परखा जाता है: Tanrei के सुलभता मानदंड उस पर लागू नहीं होते, न स्टैंडर्ड कंट्रास्ट में, न मध्यम में, न उच्च में, और बिल्ड वहाँ जो कंट्रास्ट अनुपात मापता है, वे चेतावनी के रूप में नहीं, जानकारी के रूप में दर्ज होते हैं। कार्यात्मक विफलता — ऐसा कंट्रोल जिसे चलाया न जा सके, या नाम या स्टेट का न होना — हर सिस्टम में ख़ामी है, नक़ल करने वाले प्रीसेट में भी।