openpencil/packages/docs/user-guide/variables.md
Danila Poyarkov 7ee621ec41
feat: import and export W3C design tokens (#964)
* feat(core): read and write W3C design tokens

Variables export as DTCG 2025.10 token files, one per collection mode in the shape Figma imports, with text and effect styles as typography and shadow tokens and a resolver document that combines them. OpenPencil's own token fields ride in a dev.openpencil extension, so an export reads back as it was.

Import reads plain mode files, resolver documents, and Tokens Studio themes, plans what it would add, update, or skip against the document without changing it, and applies the plan as one undo step: values merge into variables by name, nothing is deleted, and an updated style updates the layers that use it.

* feat: import and export design tokens from the variables dialog

The stylesheet menu exports the document's variables and styles as a zip of W3C design tokens, and Import design tokens reads token files, folders, or a zip into a dialog that shows where each collection and mode goes, what would be added, updated, or skipped and why, before applying it as one undo step.

* feat: import and export design tokens from tools and the CLI

openpencil tokens --format dtcg --out <folder> writes the token files, design_to_tokens takes the same format, and import_design_tokens imports token files into a document for AI, MCP, and openpencil tool call. The editor and these paths share one apply step behind a target interface: the editor makes each change undoable, a headless document takes them directly.

Re-importing an export changes nothing it does not need to: values that match are left alone, layers that use an updated style are changed only outside instances, where they follow their component, and collections that share a name keep their own files apart.

* perf(core): index token lookups when planning an import

Resolving each reference scanned every token and variable, which made importing a large design system quadratic. A resolver now also finds files picked without their folders by name.

* docs: document design token import and export

* test: type the design token result in the tokens command test

* fix: lay out the design token import dialog as a mapping list

Each collection and mode sits beside the picker for where it goes, in one bordered list, so the pickers no longer read as headings. Skipped tokens use AppCollapsible, file problems AppAlert, and the counts move to the footer.

* fix: keep durations, variable metadata, and style edits through design token import

A duration Figma's format writes in seconds goes back into a variable that holds milliseconds. Tokens without OpenPencil's extension leave an updated variable's unit, scopes, and code syntax as they are. A style token whose value was edited in another tool takes that edit instead of the stale exact fields its extension still carries. Aliases to a repeated collection name resolve within one collection, a collection named Styles no longer collides with the resolver's styles set, and the dialog plans again when the document changes and right before applying. The editor imports the apply step directly rather than the whole format barrel.

* fix: keep effect order and explicit alias targets in design token import

Edited shadows take the places of the shadows they replace, so blurs keep their positions. An alias whose Figma data names a collection that is left out or absent is missing rather than bound to the same path in another collection. The resolver reserves the Styles set name only when there is a styles file.

* perf(cli): print token stylesheets without loading every page

A CSS or Tailwind stylesheet reads only variables, which load with the document, so tokens skips populating and laying out every page as variables already does. On an 85 MB design kit this takes the command from about seven minutes to seconds.
2026-10-08 16:53:46 +00:00

7.7 KiB

title description
Variables Design variables, collections, modes, and fill bindings in OpenPencil.

Variables

Variables store reusable design tokens — colors, spacing values, and other properties — that can be bound to nodes. Change a variable's value and every node using it updates.

Opening the Variables Dialog

Open it from View → Variables…, by searching "Variables" in the command palette, or, with no nodes selected, from the Variables section of the Design tab. Expand in the dialog's corner gives it most of the window.

The dialog lists the active collection's variables on the left, edits the selected variable or the collection on the right, and shows the stylesheet they produce below. In a narrow window or on a phone it shows one mode at a time, and a variable, the collection settings, or the stylesheet opens over the list with a back button.

Collections

Variables are organized into collections. In a wide dialog they are listed in a sidebar with how many variables each holds; narrower, they are tabs, or a menu on a phone.

  • Switch collection — click it in the sidebar or its tab
  • Create collection — click + next to Collections, or the folder button in the toolbar
  • Rename or delete — with no variable selected, the right side edits the collection: change its name, or delete it from the ⋯ menu next to the name
  • Switch attribute — the attribute that turns manually switched modes on, data-theme by default for a collection named Theme; type another name, such as data-color-scheme, to match an existing codebase

Modes

Each collection can have multiple modes (e.g., Light and Dark). Modes appear as value columns in the list, and a variable has a value for each mode. Manage them in the collection settings:

  • Add mode — click + next to Modes
  • Rename — edit the mode's name
  • Duplicate, set as default, delete — use the ⋯ menu next to the mode

The default mode is Always on and goes in :root. Every other mode has Applies when, which says when the mode takes over in the exported stylesheet; the CSS it writes is shown underneath:

Applies when CSS
Switched manually the collection's switch attribute set to the mode, such as [data-theme="dark"] for a Theme collection's Dark mode
System is in dark mode / System is in light mode @media (prefers-color-scheme: dark) / light
High contrast is on @media (prefers-contrast: more)
Reduced motion is on @media (prefers-reduced-motion: reduce)
Screen is narrower than / Screen is wider than a width @media (max-width: 640px) / min-width
Container is narrower than / Container is wider than a width @container (max-width: 640px) / min-width
Custom CSS any selector, or a @media, @supports, or @container query

On the canvas, a layer shows a mode when you set the layer to it, whatever the condition. In exported code, a manually switched mode is turned on by adding its attribute to an element, so layers set to it export with that attribute. Layers set to a mode with any other condition, custom selectors included, export with literal values instead of tokens, because the stylesheet, not the layer, decides when that mode applies.

Managing Variables

Variables are grouped by the folders in their names (Brand/Primary appears as Primary under Brand), with their CSS name and one value per mode.

  • Create variable — click Create variable (or +) and pick a type; the new variable opens for editing
  • Select — click a row, or move with the arrow keys and press Enter. Shift-click selects a range, and Cmd-click (Ctrl-click on Windows and Linux) adds or removes one
  • Filter — type in the search bar to filter by name, CSS name, description, or value, such as --color-brand, a hex color, or the variable an alias points at, forgiving typos as the command palette does; click a group in the sidebar to show only that group and the groups inside it, or use the filter button to show only some types
  • Rename or edit in place — double-click a name, or a number or text value, in the list
  • Right-click — rename, duplicate, move to a group (or a new one), or delete the selected variables; Delete or Backspace deletes them too
  • Reorder — drag a row; the order is kept in the file
  • Several selected — the right side moves them into a group, duplicates them, or deletes them
  • Undo and redo — Cmd+Z and Cmd+Shift+Z or Cmd+Y (Ctrl on Windows and Linux) work in the dialog as on the canvas, one step per change. Enter commits a field and returns to the list; while a field has text you have not committed, Cmd+Z undoes the typing

Selecting a variable edits:

  • Name and CSS name — leave the CSS name empty to derive it from the name and scopes, such as --color-brand-primary. Type the name without its --; a name CSS cannot use is flagged and not saved
  • Unit — for numbers, px, rem, %, ms, s, deg, or none; values are entered in that unit
  • Value (or Values, one per mode) — a color opens the color picker. The variable button next to a value points it at another variable of the same type, an alias that follows that variable; Detach variable turns it back into the value it showed
  • CSS expression — for numbers, a value such as clamp(1rem, 4vw, 1.5rem) written instead of the number in CSS, while the canvas keeps drawing the number
  • Scopes — which properties the variable is offered for
  • Description
  • Hide from publishing — files that use this one as a library do not see the variable

Stylesheet

The bottom of the dialog shows the active collection as CSS custom properties. The copy button copies the whole document's variables as CSS or as a Tailwind v4 theme, so aliases to other collections resolve.

Importing and Exporting Design Tokens

Variables and styles move between OpenPencil, Figma, and code as W3C design tokens:

  • Export: in the stylesheet's copy menu, choose Export as design tokens. The zip holds one file per collection mode, which Figma imports as a mode; text and effect styles as typography and shadow tokens; and a resolver that combines them for tools such as Style Dictionary
  • Import: click Import design tokens in the toolbar and pick token files or a zip. Files from Figma, a resolver with the files it names, and Tokens Studio themes all work
  • Choose where it goes: before anything changes, the dialog shows each collection and mode it found and where it goes: a new collection or mode, an existing one, or nowhere. Variables and styles with the same name are updated and the rest is added; nothing is deleted. It counts what will be added, updated, and skipped, and lists why each skipped token was left out
  • The import is one step: Undo takes it all back

Binding Variables to Fills

In the Fill section of the properties panel, use the variable picker to bind a color variable to a node's fill.

  • Bind — select a color variable from the picker. The fill shows a purple badge with the variable name.
  • Detach — click the detach button on the badge to remove the binding. The fill reverts to the resolved color value.

When the variable's value changes (or when switching modes), all bound fills update automatically.

Tips

  • Use collections to group related tokens (e.g., "Primitives" for raw colors, "Semantic" for role-based aliases, "Spacing" for layout values).
  • Modes are useful for theme switching — define Light and Dark mode values in the same collection.
  • Variables support aliases — a "Semantic" collection can reference values from a "Primitives" collection.
  • See Drawing Shapes for how fills and the color picker work.