Os design tokens são o vocabulário compartilhado entre designers e desenvolvedores. Eles existem em diversas formas desde a era do Salesforce Lightning — Style Dictionary, Theo, o rascunho de especificação do W3C Design Token Community Group. O que mudou recentemente é que agora eles também são o vocabulário compartilhado entre sua base de código e os agentes de codificação com IA.
Um agente que sabe que color.accent = #d96a3a usará esse valor. Um agente que recebe uma captura de tela vai adivinhar "laranja quente" e produzir algo próximo, mas errado. A diferença se acumula ao longo de dezenas de componentes.
O figmascope exporta um tokens.json como parte de cada bundle de contexto. Este artigo explica o formato em detalhes, como o figmascope obtém os tokens do Figma, o fallback de inferência por frequência para arquivos sem Figma Variables e como conectar o output aos frameworks mais comuns. Para ver como os tokens se encaixam no workflow completo de exportação, visite o app figmascope ou leia Figma para Cursor e Figma para Claude Code.
O formato tokens.json
O figmascope usa um formato inspirado no W3C Design Token Community Group. Cada token é um objeto com campos $value e $type, aninhado sob chaves de categoria semântica:
{
"color": {
"surface": { "$value": "#f6f2ea", "$type": "color" },
"surface-2": { "$value": "#efe9dc", "$type": "color" },
"ink": { "$value": "#1f1d1a", "$type": "color" },
"ink-muted": { "$value": "#4a4641", "$type": "color" },
"accent": { "$value": "#d96a3a", "$type": "color" },
"accent-soft": { "$value": "#f2c7a8", "$type": "color" },
"good": { "$value": "#6a8f5a", "$type": "color" },
"warn": { "$value": "#c89a3a", "$type": "color" },
"bad": { "$value": "#b8553a", "$type": "color" }
},
"spacing": {
"1": { "$value": "4px", "$type": "dimension" },
"2": { "$value": "8px", "$type": "dimension" },
"3": { "$value": "12px", "$type": "dimension" },
"4": { "$value": "16px", "$type": "dimension" },
"6": { "$value": "24px", "$type": "dimension" },
"8": { "$value": "32px", "$type": "dimension" },
"12": { "$value": "48px", "$type": "dimension" },
"16": { "$value": "64px", "$type": "dimension" }
},
"radius": {
"sm": { "$value": "4px", "$type": "dimension" },
"md": { "$value": "8px", "$type": "dimension" },
"lg": { "$value": "16px", "$type": "dimension" },
"full": { "$value": "9999px", "$type": "dimension" }
},
"typography": {
"body": {
"fontFamily": { "$value": "Inter", "$type": "fontFamily" },
"fontSize": { "$value": "14px", "$type": "dimension" },
"fontWeight": { "$value": 400, "$type": "number" },
"lineHeight": { "$value": 1.45, "$type": "number" }
},
"heading": {
"sm": {
"fontFamily": { "$value": "Inter", "$type": "fontFamily" },
"fontSize": { "$value": "18px", "$type": "dimension" },
"fontWeight": { "$value": 600, "$type": "number" },
"lineHeight": { "$value": 1.25, "$type": "number" }
}
},
"mono": {
"fontFamily": { "$value": "JetBrains Mono", "$type": "fontFamily" },
"fontSize": { "$value": "13px", "$type": "dimension" },
"fontWeight": { "$value": 400, "$type": "number" }
}
}
}
Por que "inspirado no W3C" e não exatamente a especificação?
A especificação do W3C Design Token Community Group ainda é um rascunho. O figmascope segue as convenções centrais ($value, $type, grupos aninhados) mas não implementa todos os casos extremos como tipos compostos e cadeias de resolução de aliases. O output é estável o suficiente para ser consumido pelo Style Dictionary, por travessia direta de JSON ou por um modelo de linguagem — que é o consumidor primário.
Tipos de tokens em uso
| $type | Categoria | Formato do $value | Exemplo |
|---|---|---|---|
color |
cor | string hex | "#d96a3a" |
dimension |
espaçamento, raio | string CSS com unidade | "16px" |
fontFamily |
tipografia | string com nome da fonte | "Inter" |
number |
tipografia | número sem unidade | 400, 1.45 |
As cores são sempre geradas como strings hex. Se a fonte no Figma usa RGBA com opacidade parcial, o canal alpha é preservado em hex de 8 dígitos (#d96a3a80).
Como o figmascope obtém os tokens
O figmascope usa uma estratégia de obtenção em dois níveis. O Figma Variables é a fonte preferida; a inferência por frequência é o fallback.
Nível 1: Figma Variables
Se o arquivo do Figma tem Variables definidas (o sistema nativo de tokens do Figma, disponível nos planos Professional e Organization), o figmascope as lê via endpoint /v1/files/:key/variables/local da REST API. Os nomes das variáveis são usados como chaves de tokens, sanitizados para kebab-case. Os modos são colapsados para o modo padrão, a menos que o arquivo tenha um único modo, caso em que os valores desse modo são usados diretamente.
As coleções de variáveis mapeiam para as chaves de categoria de nível superior em tokens.json. Uma coleção chamada "Color" produz tokens.color.*; "Spacing" produz tokens.spacing.*. Se o seu arquivo do Figma usa nomes de coleção não padrão, o figmascope tenta inferir a categoria a partir do tipo resolvido da variável.
Nível 2: Inferência por frequência
Muitos arquivos do Figma — especialmente os mais antigos ou arquivos de clientes que não adotaram Variables — não têm definições de variáveis. O figmascope lida com isso percorrendo toda a árvore de nós e construindo histogramas de frequência de cores de preenchimento, valores de espaçamento, raios de canto e propriedades de tipografia.
Valores que aparecem acima de um limiar de frequência se tornam tokens candidatos. Eles são nomeados por sua categoria e um índice sequencial (color.0, color.1...) a menos que um nome legível por humanos possa ser inferido de como o valor é usado (ex.: uma cor usada apenas em fundos em múltiplos frames se torna color.surface).
O manifesto _meta.json registra tokensSource como "variables" ou "inferred", para que o seu prompt ao agente possa indicar quando a inferência foi usada:
// _meta.json — inferred fallback
{
"tokensSource": "inferred",
"warnings": [
{
"code": "tokens-inferred",
"message": "No Figma Variables found. Tokens were inferred from usage frequency."
}
]
}
Tokens inferidos são úteis, mas não são autoritativos. Trate-os como ponto de partida, não como especificação de sistema de design.
Referências de tokens na IR de layout
Os arquivos de IR por tela (screens/*.json) referenciam tokens por caminho usando strings $ref em vez de incorporar valores brutos. Isso mantém a IR compacta e garante que o agente sempre resolva valores de uma única fonte da verdade:
{
"kind": "stack",
"name": "PrimaryButton",
"direction": "horizontal",
"gap": { "$ref": "spacing.2" },
"padding": {
"top": 10, "right": 16, "bottom": 10, "left": 16
},
"background": { "$ref": "color.accent" },
"radius": { "$ref": "radius.sm" },
"children": [
{
"kind": "leaf",
"name": "ButtonLabel",
"type": "text",
"style": { "$ref": "typography.body" },
"color": { "$ref": "color.surface" }
}
]
}
Um agente que processa esse nó resolve color.accent para #d96a3a e spacing.2 para 8px a partir do arquivo tokens.json paralelo. Sem ambiguidade, sem alucinação de valores.
Veja per-screen IR explained para a documentação completa do esquema de nós.
Usando tokens.json com Style Dictionary
O output do figmascope é compatível com o Style Dictionary com configuração mínima. Como já usa a convenção $value / $type, você pode apontar o Style Dictionary diretamente para tokens.json:
// style-dictionary.config.js
module.exports = {
source: ['design/tokens.json'],
platforms: {
css: {
transformGroup: 'css',
prefix: 'fs',
buildPath: 'src/styles/',
files: [{ destination: 'tokens.css', format: 'css/variables' }]
},
js: {
transformGroup: 'js',
buildPath: 'src/',
files: [{ destination: 'tokens.js', format: 'javascript/es6' }]
}
}
};
Executar style-dictionary build produzirá propriedades CSS customizadas e exports de módulos ES a partir do mesmo arquivo de origem que o agente usa.
Usando tokens.json com Tailwind
Um script pequeno converte tokens.json em uma extensão de tema do Tailwind. A estrutura é plana o suficiente para percorrer sem recursão para os casos mais comuns:
// scripts/tokens-to-tailwind.js
const fs = require('fs');
const tokens = JSON.parse(fs.readFileSync('design/tokens.json', 'utf8'));
function flattenGroup(group) {
return Object.fromEntries(
Object.entries(group).map(([k, v]) => [k, v.$value])
);
}
const extend = {
colors: flattenGroup(tokens.color),
spacing: flattenGroup(tokens.spacing),
borderRadius: flattenGroup(tokens.radius),
};
console.log(JSON.stringify(extend, null, 2));
node scripts/tokens-to-tailwind.js > design/tailwind-extend.json
Em seguida, no tailwind.config.ts:
import extend from './design/tailwind-extend.json';
export default {
content: ['./src/**/*.{ts,tsx}'],
theme: { extend },
};
Usando tokens.json com Jetpack Compose
Para projetos Android, a estrutura de tokens mapeia bem para um object em Kotlin. Você pode gerá-lo programaticamente ou pedir ao Claude Code para fazer isso. Para tokens de cor:
// Generated from design/tokens.json
object DesignTokens {
object Color {
val surface = Color(0xFFF6F2EA)
val ink = Color(0xFF1F1D1A)
val accent = Color(0xFFD96A3A)
val accentSoft = Color(0xFFF2C7A8)
}
object Spacing {
val s1 = 4.dp
val s2 = 8.dp
val s4 = 16.dp
val s8 = 32.dp
}
}
Veja Jetpack Compose from Figma para um guia completo incluindo integração com MaterialTheme.
O que tokens.json não contém
Conhecer os limites de escopo ajuda a definir expectativas corretas:
- Sombras — o figmascope atualmente não exporta tokens de drop-shadow ou inner-shadow. Os valores de sombra aparecem inline nos nós da IR onde presentes.
- Gradientes — preenchimentos com gradiente são exportados como estão nos nós leaf da IR, não como tokens nomeados.
- Animações — valores de timing, easing e transição estão fora do escopo. O suporte a animações do Figma está no modo Prototype, que o figmascope não lê.
- Breakpoints — restrições responsivas não são um conceito do Figma no nível de variáveis; elas requerem decisões de design separadas.
O array warnings em _meta.json notará quaisquer valores que não puderam ser exportados corretamente. Revise-o antes de entregar o bundle para um agente.
Como os nomes dos tokens são derivados
Quando o figmascope lê Figma Variables, o nome da variável no Figma se torna a chave do token. Uma variável chamada Colors/Surface/Primary em uma coleção chamada Color se torna tokens.color.surface.primary em tokens.json — o separador de caminho é / no Figma e . nas chaves aninhadas do JSON.
O Figma permite nomes de variáveis com espaços, letras maiúsculas e caracteres especiais. O figmascope normaliza esses casos:
- Espaços se tornam hífens:
Primary Surface→primary-surface - Maiúsculas são convertidas para minúsculas:
AccentOrange→accent-orange - Caracteres de controle e marcas Unicode bidi são removidos via
sanitizeName - Scripts cirílicos e outros não-latinos são transliterados para compatibilidade com slugs
A etapa de transliteração é importante para equipes internacionais. Uma equipe de design ucraniana usando nomes de variáveis cirílicos como Фон (fundo) obtém uma chave ASCII estável (fon) no output, que é utilizável em nomes de classe CSS e JSON sem problemas de codificação. O nome original é preservado como campo $description se presente nos metadados da Figma Variable.
Verificando a cobertura de tokens antes da geração de código
Antes de entregar o bundle para um agente, vale verificar se a cobertura de tokens parece razoável. Um script Node rápido que verifica se todos os valores de cor referenciados nas IRs de tela resolvem para entradas em tokens.json:
// scripts/check-token-coverage.js
const fs = require('fs');
const glob = require('glob');
const tokens = JSON.parse(fs.readFileSync('design/tokens.json', 'utf8'));
const screenFiles = glob.sync('design/screens/*.json');
function getRef(obj) {
const refs = [];
if (obj && typeof obj === 'object') {
if (obj.$ref) refs.push(obj.$ref);
for (const v of Object.values(obj)) refs.push(...getRef(v));
}
return refs;
}
function resolveRef(ref, tokens) {
return ref.split('.').reduce((o, k) => o?.[k], tokens);
}
let missing = 0;
for (const file of screenFiles) {
const screen = JSON.parse(fs.readFileSync(file, 'utf8'));
for (const ref of getRef(screen)) {
if (!resolveRef(ref, tokens)) {
console.error(`Missing token: ${ref} (in ${file})`);
missing++;
}
}
}
if (missing === 0) console.log('All token refs resolve.');
else console.error(`${missing} unresolved token refs.`);
Zero refs faltando significa que o agente conseguirá resolver cada $ref na IR de layout sem inventar valores. Se houver refs faltando, geralmente significa que o arquivo do Figma mudou após a exportação do bundle — execute o figmascope novamente para obter uma exportação atualizada. Você também pode conferir o blog do figmascope para mais dicas sobre como manter a cobertura de tokens entre iterações de design.