Figma Token Sync
Keep the processed CSS tokens (from ETL) aligned with the JavaScript theme
objects used for React Native.
Pipeline: Figma → JSON → CSS/Tailwind (automated) → JS themes (manual sync).
CSS is the source of truth; the JS theme.dark.ts / theme.light.ts files are
the sync targets.
Never hardcode the brand/theme list
Brands come and go (today: enterprise, ledger-live, websites — but discover,
don't assume). Always enumerate them from the filesystem so a new brand can't be
silently missed:
bash .claude/skills/figma-token-sync/scripts/discover-themes.sh
This prints the CSS brands, the JS brands, every JS theme file that must be
updated together, and warns if the two sides disagree.
Gap analysis
For a brand + category, compare CSS coverage against JS and list the token names
present in CSS but missing from JS:
bash .claude/skills/figma-token-sync/scripts/compare-tokens.sh <brand> <category>
# e.g. compare-tokens.sh ledger-live background
Run it for each category you touched (background, border, text, …) across
every brand from the discovery step.
Applying updates
- Update every JS theme file the discovery script listed — never just one.
Partial updates create per-brand inconsistencies.
- Reference primitives, never hardcode values, and use the correct
light/dark primitive set:
// CSS is kebab-case, JS is camelCase
'--color-border-base-inverted' → baseInverted
'--color-background-surface-disabled' → surfaceDisabled
// ✅ reference the primitive
baseInverted: primitiveColorTokens.dark.grey['050']
// ❌ never hardcode
baseInverted: '#ffffff'
Validate
npx tsc --noEmit --project libs/design-core/tsconfig.json
npx nx lint @ledgerhq/lumen-design-core --fix
npx nx build @ledgerhq/lumen-design-core
If you touched the ETL rather than the themes, it lives in internals/sync-figma
— see its README.md.
Checklist:
Troubleshooting
- Counts differ: rerun
compare-tokens.sh to see which token names are
CSS-only.
- Type errors: the new token must match the TypeScript theme interface.
- A brand looks stale: rerun
discover-themes.sh — it may be new since the
last sync, or present on only one side (it warns about that).