<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>design-tokens on Socle</title><link>https://socle.uncinq.dev/docs/design-tokens/</link><description>Recent content in design-tokens on Socle</description><generator>Hugo</generator><language>en</language><atom:link href="https://socle.uncinq.dev/docs/design-tokens/index.xml" rel="self" type="application/rss+xml"/><item><title>Naming</title><link>https://socle.uncinq.dev/docs/design-tokens/naming/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/naming/</guid><description>&lt;p&gt;A token name is an API. Once a project references &lt;code&gt;--color-text-muted&lt;/code&gt;, renaming it is a breaking change, so the grammar below is worth following closely.&lt;/p&gt;
&lt;h2 id="semantic-tokens"&gt;Semantic tokens&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;--{category}-{subcategory?}-{variant?}-{state?}
&lt;/code&gt;&lt;/pre&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Pattern&lt;/th&gt;
 &lt;th&gt;Example&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--{category}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--color&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--{category}-{subcategory}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--color-text&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--{category}-{subcategory}-{variant}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--color-text-muted&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--{category}-{subcategory}-{state}&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;--color-text-disabled&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="component-tokens"&gt;Component tokens&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;--{component}-{property}-{sub-property?}-{state?}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The property mirrors the CSS property name, so the token reads the same way as the declaration it controls. Colors are the exception: &lt;code&gt;color&lt;/code&gt; leads and the role follows, for the reason given in the rules below.&lt;/p&gt;</description></item><item><title>Colors</title><link>https://socle.uncinq.dev/docs/design-tokens/colors/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/colors/</guid><description>&lt;h2 id="color-space-oklch"&gt;Color space, OKLCH&lt;/h2&gt;
&lt;p&gt;Every primitive color is defined in OKLCH.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Channel&lt;/th&gt;
 &lt;th&gt;Range&lt;/th&gt;
 &lt;th&gt;Meaning&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;L&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;0 to 1&lt;/td&gt;
 &lt;td&gt;Perceptual lightness, 0 is black and 1 is white&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;C&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;0 to about 0.4&lt;/td&gt;
 &lt;td&gt;Chroma, or colorfulness, where 0 is gray&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;H&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;0 to 360 degrees&lt;/td&gt;
 &lt;td&gt;Hue angle&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Why OKLCH rather than hex or HSL:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Perceptually uniform.&lt;/strong&gt; Equal steps in &lt;code&gt;L&lt;/code&gt; produce equal perceived brightness differences, whatever the hue. HSL does not guarantee this: &lt;code&gt;hsl(60, 100%, 50%)&lt;/code&gt; yellow looks far brighter than &lt;code&gt;hsl(240, 100%, 50%)&lt;/code&gt; blue at the same stated lightness.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Predictable contrast.&lt;/strong&gt; You can reason about WCAG contrast by comparing &lt;code&gt;L&lt;/code&gt; values, without converting to relative luminance first.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better interpolation.&lt;/strong&gt; Gradients and animations between two OKLCH colors do not pass through muddy grays.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Composable.&lt;/strong&gt; The relative color syntax, &lt;code&gt;oklch(from var(--color-text) l c h / 0.6)&lt;/code&gt;, lets a token derive from another without duplicating its value. Several semantic tokens in this package rely on it.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Browser support is Chrome 111, Firefox 113 and Safari 15.4 and above. No sRGB fallback is generated, so every value ships as &lt;code&gt;oklch()&lt;/code&gt; and anything older needs a fallback of its own.&lt;/p&gt;</description></item><item><title>Dark mode</title><link>https://socle.uncinq.dev/docs/design-tokens/dark-mode/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/dark-mode/</guid><description>&lt;p&gt;The dark theme is an &lt;strong&gt;overlay&lt;/strong&gt;, not a second palette. &lt;code&gt;tokens/themes/dark.json&lt;/code&gt; re-declares 13 semantic tokens and nothing else. Every other token, including the whole primitive palette, is shared.&lt;/p&gt;
&lt;p&gt;That is the point of the semantic layer: if a component reads &lt;code&gt;--color-background&lt;/code&gt; rather than &lt;code&gt;--color-white&lt;/code&gt;, it needs no dark-mode branch of its own.&lt;/p&gt;
&lt;h2 id="what-it-overrides"&gt;What it overrides&lt;/h2&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Token&lt;/th&gt;
 &lt;th&gt;Light&lt;/th&gt;
 &lt;th&gt;Dark&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-background&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;white&lt;/td&gt;
 &lt;td&gt;gray-950&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-background-disabled&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-100&lt;/td&gt;
 &lt;td&gt;gray-900&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-background-media&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-200&lt;/td&gt;
 &lt;td&gt;gray-800&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-background-muted&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-100&lt;/td&gt;
 &lt;td&gt;gray-900&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-background-muted-hover&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-200&lt;/td&gt;
 &lt;td&gt;gray-800&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-border&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-200&lt;/td&gt;
 &lt;td&gt;gray-800&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-heading&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;black&lt;/td&gt;
 &lt;td&gt;white&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-shadow&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;black&lt;/td&gt;
 &lt;td&gt;white&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-text&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-900&lt;/td&gt;
 &lt;td&gt;gray-200&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-text-disabled&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-300&lt;/td&gt;
 &lt;td&gt;gray-600&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-text-hover&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-700&lt;/td&gt;
 &lt;td&gt;gray-300&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--color-text-muted&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;derived from &lt;code&gt;--color-text&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;gray-400&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;--form-color-background&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;white&lt;/td&gt;
 &lt;td&gt;gray-900&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Two of these do more work than they look. &lt;code&gt;--color-shadow&lt;/code&gt; flipping to white inverts the entire shadow system in one line, because &lt;code&gt;--color-shadow-light&lt;/code&gt;, &lt;code&gt;-medium&lt;/code&gt; and &lt;code&gt;-strong&lt;/code&gt; all derive from it with relative color syntax. And &lt;code&gt;--color-background-surface&lt;/code&gt; is not in the list at all, because it aliases &lt;code&gt;--color-background&lt;/code&gt; and follows for free.&lt;/p&gt;</description></item><item><title>Customizing</title><link>https://socle.uncinq.dev/docs/design-tokens/customizing/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/customizing/</guid><description>&lt;p&gt;There are two ways to change what this package produces. Pick by how deep the change goes, not by preference.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Need&lt;/th&gt;
 &lt;th&gt;Approach&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Change the brand, the typography, a handful of tokens&lt;/td&gt;
 &lt;td&gt;CSS &lt;code&gt;@layer tokens&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Add a few project-specific tokens&lt;/td&gt;
 &lt;td&gt;CSS &lt;code&gt;@layer tokens&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Redefine the primitive palette entirely&lt;/td&gt;
 &lt;td&gt;JSON plus build&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Add many project tokens, or generate other formats&lt;/td&gt;
 &lt;td&gt;JSON plus build&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="1-css-override"&gt;1. CSS override&lt;/h2&gt;
&lt;p&gt;Every token lives in &lt;code&gt;@layer tokens&lt;/code&gt;, the lowest-priority layer in the recommended order. Any &lt;code&gt;@layer tokens&lt;/code&gt; block imported &lt;strong&gt;after&lt;/strong&gt; this package wins on source order, with no specificity tricks required.&lt;/p&gt;</description></item><item><title>Reference</title><link>https://socle.uncinq.dev/docs/design-tokens/reference/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/reference/</guid><description>&lt;p&gt;Every table below is generated at build time from &lt;code&gt;dist/tokens.json&lt;/code&gt;, which Style Dictionary produces from the same JSON sources as the CSS. Nothing here is written by hand, so a token cannot appear in the reference without existing in the package, or change value without the page changing with it.&lt;/p&gt;
&lt;p&gt;Values are shown as they are emitted. A semantic token that references a primitive shows &lt;code&gt;var(--the-primitive)&lt;/code&gt; rather than a flattened value, because that is literally what ships, and it is what makes an override of the primitive propagate.&lt;/p&gt;</description></item><item><title>DTCG format</title><link>https://socle.uncinq.dev/docs/design-tokens/dtcg/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/dtcg/</guid><description>&lt;p&gt;The &lt;a href="https://www.w3.org/community/design-tokens/"&gt;W3C Design Token Community Group (DTCG)&lt;/a&gt; defines a standard interchange format for design tokens, so they can travel between tools (Figma, code, documentation) without loss of meaning.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;@uncinq/design-tokens&lt;/code&gt; uses DTCG JSON as its source format. &lt;a href="https://styledictionary.com/"&gt;Style Dictionary v5&lt;/a&gt; transforms those JSON files into CSS custom properties — see &lt;a href="https://socle.uncinq.dev/docs/design-tokens/style-dictionary/"&gt;STYLE-DICTIONARY.md&lt;/a&gt; for the build pipeline. The DTCG spec informs the architecture (primitive → semantic → component, naming conventions, token types).&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="the-dtcg-format"&gt;The DTCG format&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://tr.designtokens.org/format/"&gt;DTCG spec&lt;/a&gt; defines tokens as JSON objects with reserved &lt;code&gt;$&lt;/code&gt;-prefixed keys:&lt;/p&gt;</description></item><item><title>Style Dictionary</title><link>https://socle.uncinq.dev/docs/design-tokens/style-dictionary/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/style-dictionary/</guid><description>&lt;p&gt;&lt;a href="https://styledictionary.com/"&gt;Style Dictionary v5&lt;/a&gt; transforms the DTCG JSON token files into CSS custom properties.&lt;/p&gt;
&lt;h2 id="run-the-build"&gt;Run the build&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;npm run build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Output is written to &lt;code&gt;dist/css/&lt;/code&gt;. One CSS file is generated per JSON source file, preserving the same directory structure:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;tokens/primitive/color.json → dist/css/primitive/color.css
tokens/semantic/color.json → dist/css/semantic/color.css
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id="config--style-dictionaryconfigjs"&gt;Config — &lt;code&gt;style-dictionary.config.js&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The config is a single ES module. It registers a custom name transform and a custom format, then maps every JSON file to a CSS output.&lt;/p&gt;</description></item><item><title>Fluid scales</title><link>https://socle.uncinq.dev/docs/design-tokens/utopia/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://socle.uncinq.dev/docs/design-tokens/utopia/</guid><description>&lt;p&gt;Source: &lt;a href="https://utopia.fyi"&gt;https://utopia.fyi&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="principle"&gt;Principle&lt;/h2&gt;
&lt;p&gt;Each fluid token is a &lt;code&gt;clamp()&lt;/code&gt; expression that scales linearly between a minimum and a maximum value, with no breakpoints.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-css" data-lang="css"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;property&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt; &lt;span style="color:#f92672"&gt;clamp&lt;/span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#f92672"&gt;min&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;intercept&lt;/span&gt; &lt;span style="color:#f92672"&gt;+&lt;/span&gt; &lt;span style="color:#f92672"&gt;slope&lt;/span&gt; &lt;span style="color:#960050;background-color:#1e0010"&gt;×&lt;/span&gt; &lt;span style="color:#f92672"&gt;1vw&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; &lt;span style="color:#f92672"&gt;max&lt;/span&gt;&lt;span style="color:#f92672"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;slope = (max_px − min_px) / (viewport_max − viewport_min)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;intercept = min_px − slope × viewport_min (÷ 16 → rem)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;
&lt;h2 id="viewport-range"&gt;Viewport range&lt;/h2&gt;
&lt;p&gt;All fluid tokens use the same viewport range: &lt;strong&gt;375 px → 1440 px&lt;/strong&gt; (range = 1065).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;slope = (max_px − min_px) / 1065
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;intercept = min_px − slope × 375 (÷ 16 → rem)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This range covers modern phones (375 px) to wide desktop screens (1440 px). Tokens are clamped at both ends — below 375 px they stay at &lt;code&gt;min&lt;/code&gt;, above 1440 px they stay at &lt;code&gt;max&lt;/code&gt;.&lt;/p&gt;</description></item></channel></rss>