If your designers hand you a Figma file with 14 text styles named "Heading/H3/Semibold/Mobile" and you hard-code them per component, you are maintaining three sources of truth that drift apart. Typography tokens fix this.
The token model
Separate primitive from semantic:
{ "primitive": { "fontSize": { "100": "0.75rem", "200": "0.875rem", "300": "1rem", "500": "1.25rem", "700": "1.75rem", "900": "2.5rem" } }, "semantic": { "heading-lg": { "fontSize": "500", "fontWeight": "600", "lineHeight": "1.2" }, "body-default": { "fontSize": "300", "fontWeight": "400", "lineHeight": "1.5" }, "label-small": { "fontSize": "100", "fontWeight": "500", "lineHeight": "1.3", "letterSpacing": "0.02em" } } } Components reference semantic tokens only. When the scale changes, you edit primitives - every heading in the product updates together.
The typeface is a token too
Model the font family stack as a primitive (fontFamily.sans, fontFamily.mono) with the full fallback chain baked in. When the brand team swaps the typeface, one token changes. And when an audit asks what the legacy build actually renders - a question that comes up in every design-system migration - screenshot the page and identify it on-device. Typeye names the rendered typeface from a screenshot locally, so migrating to tokens starts from facts instead of guesses.
Ship it as code
Style Dictionary transforms the JSON into CSS custom properties, Sass variables, and platform formats. The Figma plugin reads the same source. One JSON file, every platform consistent.
The migration trap
Existing pages were built with hard-coded values that nobody can name. Before writing tokens, screenshot the current pages and identify the real rendered fonts and sizes - then encode reality, not aspiration. Start at typeye.com.