Creating Design System Rules for Figma-to-Code Workflows in Plugins: Architecture and Implementation
OpenAI Plugins enforces design system rules by separating primitive tokens from semantic tokens, restricting variable scopes to specific UI roles, and embedding platform-specific code syntax to generate production-ready CSS, Android, and iOS variables from Figma files.
The OpenAI Plugins repository ships a full-stack Figma integration that transforms static designs into maintainable code. By implementing strict architectural patterns when creating design system rules for Figma-to-code workflows in plugins, developers ensure that generated token collections remain idempotent across multiple runs while supporting Light, Dark, and high-contrast modes.
Understanding the Figma-to-Code Pipeline Architecture
The workflow is orchestrated by the /implement-from-figma command defined in plugins/figma/commands/implement-from-figma.md. This command parses a Figma URL, extracts node IDs, captures screenshots, and delegates to a design-system generator that executes a series of token-creation scripts.
The Command Layer
When a user invokes /implement-from-figma, the system fetches the Figma file and initializes the token pipeline. The command hands off to scripts located in plugins/figma/skills/figma-generate-library/references/token-creation.md, which handle collection creation, primitive variable definition, and semantic aliasing.
Token Creation and Collections
The pipeline distinguishes between two fundamental collection types:
- Primitive collections store raw design values (HEX colors, spacing units) with
scopes = []to hide them from designer pickers. - Semantic collections expose aliased variables with targeted scopes (e.g.,
FRAME_FILL,SHAPE_FILL) that map to specific UI component roles.
Each variable must carry code syntax metadata for Web (var(--...) wrapper mandatory), Android, and iOS to enable Dev Mode handoff.
Design-System Rules for Token Architecture
Strict adherence to these rules prevents token leakage and ensures deterministic builds.
Separate Primitives from Semantics
Primitive variables are mode-agnostic values stored in a collection named Primitives. Semantic variables reside in collections like Color or Spacing and reference primitives via VARIABLE_ALIAS for each mode (Light, Dark, etc.).
This separation enables global changes—updating a single primitive updates every semantic alias across all modes. In token-creation.md, primitives are created with v.scopes = [] while semantic variables receive explicit scopes like v.scopes = ['FRAME_FILL','SHAPE_FILL'].
Scope Variables Precisely (Never Use ALL_SCOPES)
Never assign ALL_SCOPES to design tokens. Broad scoping floods every Figma picker with irrelevant tokens, violating the principle of least privilege.
Instead, assign specific scopes based on the variable's intended use. The reference table in plugins/figma/skills/figma-use/references/variable-patterns.md maps scopes to design-system roles:
FRAME_FILLfor background colorsSHAPE_FILLfor component fillsTEXT_FILLfor typography colors
Enforce Code Syntax for Web, Android, and iOS
Every variable must declare platform-specific code syntax using setVariableCodeSyntax. For Web output, the value must wrap the CSS variable in var():
variable.setVariableCodeSyntax('WEB', 'var(--color-bg-primary)');
Without this wrapper, Figma Dev Mode displays raw hex values rather than the CSS variable reference. Android and iOS syntax strings follow the same pattern but omit the var() wrapper.
Maintain Idempotency with Shared Plugin Data
All created entities must be tagged with sharedPluginData to prevent duplication on re-runs. The standard keys are:
'dsb'– namespace'run_id'– unique execution identifier'key'– semantic path (e.g.,'collection/primitives','color/bg/primary')
This tagging enables the "check-before-create" logic that makes the pipeline idempotent.
Implementing the Token Pipeline
Creating Primitive Collections
Begin by initializing a collection for raw values. In plugins/figma/skills/figma-generate-library/references/token-creation.md, the implementation follows this pattern:
const RUN_ID = "dsb-2024-01";
const primColl = figma.variables.createVariableCollection("Primitives");
primColl.renameMode(primColl.modes[0].modeId, "Value");
primColl.setSharedPluginData('dsb', 'run_id', RUN_ID);
primColl.setSharedPluginData('dsb', 'key', 'collection/primitives');
Primitives are populated with empty scopes to hide them from the UI:
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const primColl = collections.find(c => c.getSharedPluginData('dsb','key') === 'collection/primitives');
const valueMode = primColl.modes[0].modeId;
const palette = [
{ name: 'blue/500', hex: '#3B82F6' },
{ name: 'gray/900', hex: '#111827' },
];
for (const {name, hex} of palette) {
const v = figma.variables.createVariable(name, primColl, 'COLOR');
v.setValueForMode(valueMode, hexToRgb(hex));
v.scopes = []; // hide from UI
v.setVariableCodeSyntax('WEB', `var(--${name.replace('/','-')})`);
v.setSharedPluginData('dsb','run_id',RUN_ID);
v.setSharedPluginData('dsb','key',`primitive/${name}`);
}
Building Semantic Variables with Mode Aliasing
Semantic variables reference primitives via createVariableAlias. First, retrieve the mode IDs from the semantic collection:
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const primColl = collections.find(c => c.getSharedPluginData('dsb','key') === 'collection/primitives');
const colorColl = collections.find(c => c.getSharedPluginData('dsb','key') === 'collection/color');
const lightMode = colorColl.modes.find(m => m.name === 'Light').modeId;
const darkMode = colorColl.modes.find(m => m.name === 'Dark').modeId;
function getPrim(name) {
const v = allVars.find(v => v.getSharedPluginData('dsb','key') === `primitive/${name}`);
if (!v) throw new Error(`Missing primitive ${name}`);
return v;
}
Create the semantic variable and bind it to primitives for each mode:
const v = figma.variables.createVariable('color/bg/primary', colorColl, 'COLOR');
v.setValueForMode(lightMode, figma.variables.createVariableAlias(getPrim('white/1000')));
v.setValueForMode(darkMode, figma.variables.createVariableAlias(getPrim('gray/900')));
v.scopes = ['FRAME_FILL','SHAPE_FILL'];
v.setVariableCodeSyntax('WEB', 'var(--color-bg-primary)');
v.setSharedPluginData('dsb','run_id',RUN_ID);
v.setSharedPluginData('dsb','key','color/bg/primary');
Validation and Error Recovery
After each phase, run validation scripts to catch missing scopes or broken aliases. The token-creation.md reference includes verification helpers:
const collections = await figma.variables.getLocalVariableCollectionsAsync();
const allVars = await figma.variables.getLocalVariablesAsync();
const missingScopes = allVars.filter(v => v.scopes.length === 0 && v.resolvedType !== 'BOOLEAN');
if (missingScopes.length) console.warn('Unscoped non-primitive vars:', missingScopes);
For error recovery after failed use_figma calls, consult plugins/figma/skills/figma-use/references/validation-and-recovery.md.
Summary
- Separate concerns by storing raw values in primitive collections (hidden scopes) and design tokens in semantic collections with specific scopes.
- Avoid
ALL_SCOPESto keep Figma pickers clean; use targeted scopes likeFRAME_FILLandTEXT_FILLas defined invariable-patterns.md. - Wrap Web syntax in
var()usingsetVariableCodeSyntax('WEB', 'var(--token)')to ensure Dev Mode displays usable CSS. - Tag every entity with
sharedPluginDatakeys (run_id,key) under the'dsb'namespace to enable idempotent re-runs. - Validate after each phase using the count and alias verification scripts from
token-creation.mdto prevent downstream errors.
Frequently Asked Questions
How do I prevent duplicate variables when re-running the Figma-to-code pipeline?
Tag every created collection and variable with setSharedPluginData('dsb', 'run_id', RUN_ID) and setSharedPluginData('dsb', 'key', uniqueKey). Before creation, query existing variables using getSharedPluginData('dsb', 'key') to check for existence, ensuring the script remains idempotent across multiple executions.
Why must Web code syntax use the var() wrapper?
Figma Dev Mode requires the var() wrapper to recognize and display CSS custom properties. Without it, the interface shows raw hex values, breaking the design-to-code handoff. Always call variable.setVariableCodeSyntax('WEB', 'var(--token-name)') when creating semantic variables.
What is the difference between primitive and semantic variable collections?
Primitive collections store raw, mode-agnostic values (e.g., blue/500 = #3B82F6) with scopes = [] to hide them from designers. Semantic collections contain variables that reference primitives via aliases and carry specific modes (Light, Dark) and scopes (e.g., FRAME_FILL), serving as the API between design and engineering.
Where are the validation scripts for checking broken aliases?
Validation helpers are documented in plugins/figma/skills/figma-generate-library/references/token-creation.md under the "Validation" section. These scripts verify that every semantic variable resolves to a valid primitive alias and that all non-primitive variables have explicit scopes assigned.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →