DTCG extensions
DTCG 2025.10 reserves $extensions for vendor data. What the specification cannot express, Syntope stores there under the eu.syntope.* namespace. Every file Syntope Engine writes is checked against the official schema, so files stay valid DTCG, and a tool that ignores these keys still reads the standard tokens.
A DTCG file without any Syntope keys is ordinary input. You never need to add them yourself.
Early beta. File metadata can still change between versions.
Keys on tokens and files
| Key | Where | Holds | What other DTCG tools see |
|---|---|---|---|
eu.syntope.stringTokens |
Root of a token file | String tokens, keyed by token path | Nothing, unless they read the extension |
eu.syntope.formula |
On a dimension or number token | A calculation | One calculated $value, for one theme |
eu.syntope.colorExpression |
On a color token | A base colour and one change | One calculated $value, for one theme |
eu.syntope.figma |
On a typography or number token | Figma text properties | The standard $value |
eu.syntope.transition |
On a transition token | The CSS property from a Tokens Studio export. Carried for other tools, Syntope does not apply it. |
The standard $value |
String tokens
DTCG 2025.10 has no string type, so a file cannot hold "$type": "string" in its token tree. The engine moves each string token into the root $extensions of its own file. A group left empty by the move stays in the file.
{ "label": {}, "$extensions": { "eu.syntope.stringTokens": { "label.greeting": { "$type": "string", "$value": "Hello" } } }}Only another string token or a Syntope extension field can reference a string token. A standard token that references one cannot be exported. Do instead: give the standard token a literal value, or make it a string token too. See String.
Calculated values
DTCG 2025.10 has no arithmetic and no colour functions. A calculated token keeps its calculation in $extensions, and $value holds the result for tools that do not calculate.
{ "size": { "$type": "dimension", "base": { "$value": { "value": 8, "unit": "px" } }, "double": { "$value": { "value": 16, "unit": "px" }, "$extensions": { "eu.syntope.formula": { "expression": "{size.base} * 2", "unit": "px" } } } }, "color": { "$type": "color", "brand": { "$value": { "colorSpace": "srgb", "components": [0, 0.4, 1] } }, "soft": { "$value": { "colorSpace": "srgb", "components": [0, 0.4, 1], "alpha": 0.5 }, "$extensions": { "eu.syntope.colorExpression": { "base": "{color.brand}", "change": { "type": "alpha", "amount": 0.5 } } } } }}| Field | Rule |
|---|---|
formula.expression |
The calculation, with references in {} |
formula.unit |
Required on a dimension token, not allowed on a number token |
colorExpression.base |
A whole reference to a color token, or a DTCG colour |
colorExpression.change.type |
lighten, darken, mix or alpha |
colorExpression.change.space |
lch, hsl, srgb, p3 or oklch. Required except for alpha |
colorExpression.change.amount |
A number, or the text of a number formula |
colorExpression.change.color |
The second colour, only for mix |
Syntope never reads the stored $value of a calculated token. It calculates the value itself, per theme.
One $value per token. The engine refreshes $value each time it writes a file, using the theme the token’s set is shown in (for a set in no theme, the theme in use). A tool that does not calculate reads that one result, even where another theme would give a different value. Do instead: if another tool needs the value of each theme, give the token a plain value in each theme’s set.
A calculated token with no value in that theme blocks the export, and an edit that causes this is refused.
The token form in Syntope Tokens, the Figma plugin, does not offer calculations in this beta. A token that carries one shows its result, and typing a new value replaces the calculation. Do instead: add or change the calculation in the JSON editor, through an AI app, or by importing it.
Figma text properties
Figma can do more with text than DTCG typography can express, and DTCG forbids extra keys in a typography $value. These fields go in eu.syntope.figma on a typography token.
{ "text": { "body": { "$type": "typography", "$value": { "fontFamily": "Inter", "fontSize": { "value": 16, "unit": "px" }, "fontWeight": 400, "letterSpacing": { "value": 0, "unit": "px" }, "lineHeight": 1.5 }, "$extensions": { "eu.syntope.figma": { "lineHeight": { "unit": "PIXELS", "value": 24 }, "textCase": "UPPER" } } } }}| Field | Holds |
|---|---|
paragraphSpacing, paragraphIndent |
A DTCG dimension |
textDecoration |
NONE, UNDERLINE or STRIKETHROUGH |
textCase |
ORIGINAL, UPPER, LOWER, TITLE, SMALL_CAPS or SMALL_CAPS_FORCED |
fontStyle |
The exact Figma face, such as Medium Italic |
lineHeight |
{ "unit": "PIXELS", "value": 24 }, { "unit": "PERCENT", "value": 150 } or { "unit": "AUTO" } |
letterSpacing |
A percentage of the font size, such as -2% |
keep |
The DTCG typography fields left to the layer when the token is applied |
Each field can hold a reference to another token instead of a literal.
fontStyle, lineHeight and letterSpacing take precedence over the matching standard fields in Syntope and in Figma. So that other tools read sensible values, the engine refreshes literal fontWeight, lineHeight and letterSpacing values in $value from them each time it writes a file.
On a number token, the only field is lineHeight, with the unit alone: { "unit": "PERCENT" } or { "unit": "AUTO" }. $value is the ratio for PERCENT and 1.2 for AUTO. A pixel line height is a dimension token, not a marked number. See Typography and Number.
Keys that keep project structure
These keys let the plugin read back exactly what it wrote. The engine reads them back into the project’s structure, and they change no token value. A tool that ignores them loses nothing it needs.
| Key | Where | Holds |
|---|---|---|
eu.syntope.tokenSource |
Root of a token file | The set’s id, location and order |
eu.syntope.resolverSet |
On a set in the Resolver file | id and order |
eu.syntope.resolverModifier |
On a modifier in the Resolver file | id and order |
eu.syntope.authoring |
On the Base set in the Resolver file | version, the sidebar order (sidebarOrder) and theme groups with one theme (disabledThemeGroups) |
eu.syntope.tokenSources |
Under $defs in a single-file project, not in $extensions |
Token sets that a single Resolver file has no other place for, such as sets left out of Base and every theme |
Token IDs are not written to files. See Stable IDs.
What happens to extensions
- Other vendors’ extensions stay. The engine keeps any other namespace on a token as it found it.
- Changing a token’s type in the plugin removes
eu.syntope.formula,eu.syntope.colorExpression,eu.syntope.figmaandeu.syntope.transitionfrom it, because their meaning depends on the type. Undo in the plugin restores them, for up to 50 steps and until the plugin closes. - A Tokens Studio export is converted without reading any
eu.syntope.*key it contains. The conversion writes its own.
