Skip to content

spike: Figma token sync — native JSON approach (no DTCG, no Style Dictionary) - #2774

Open
peterliu (peterInTown) wants to merge 1 commit into
mainfrom
figma-token-sync-native-json
Open

spike: Figma token sync — native JSON approach (no DTCG, no Style Dictionary)#2774
peterliu (peterInTown) wants to merge 1 commit into
mainfrom
figma-token-sync-native-json

Conversation

@peterInTown

Copy link
Copy Markdown
Contributor

Summary

  • Replaces the DTCG + Style Dictionary approach from the original spike (spike: Figma token sync pipeline for Android #2704) with a simpler pipeline
  • fetch.ts calls the Figma Variables API and writes directly to the existing bpk-foundations-android JSON format
  • The existing buildSrc Kotlin pipeline (KotlinPoet formatters, all Gradle tasks) runs completely unchanged
  • No DTCG. No Style Dictionary. No changes to any Android source files. Node.js is only needed for the fetch step

Pipeline:

npm run tokens:fetch
  → fetch.ts: Figma Variables API → base.raw.android.json (bpk-foundations format)
  → ./gradlew generateTokens (existing, unchanged)
  → BpkColors.kt, BpkSpacing.kt, BpkBorderRadius.kt, BpkBorderSize.kt,
    BpkDuration.kt, BpkElevation.kt, BpkFontSize.kt, BpkTypography.kt, .xml files

Token coverage vs old bpk-foundations-android:

Category Old New
Semantic colors 34 38 ✅
Spacing 17 29 ✅
Radii 7 8 ✅
Borders 3 3 ✅
Elevation 6 6 ✅
Animations 3 3 ✅
Font sizes 13 46 ✅
Letter spacings 1 20 ✅
Line heights 15 48 ✅

Higher counts reflect tokens added to Figma since the package was last published.

Context

See PoC doc and implementation approaches decision for background on why this approach was explored over the original DTCG spike.

Test plan

  • Run cd token-sync && npm install && npm run tokens:fetch — verify token-sync/tokens/base.raw.android.json is written
  • Run ./gradlew generateTokens — verify BUILD SUCCESSFUL and all token files regenerated
  • Check BpkColors.kt, BpkSpacing.kt, BpkFontSize.kt have expected values

Not yet done (next steps)

  • Update GitHub Actions workflow to use new pipeline (remove Style Dictionary step)
  • Component colours (BpkButtonColors.kt etc.)
  • Figma webhook integration
  • iOS equivalent

🤖 Generated with Claude Code

Replaces the DTCG/Style Dictionary approach from the original spike with a
simpler pipeline: fetch.ts calls the Figma Variables API and writes directly
to the existing bpk-foundations-android JSON format, allowing the existing
buildSrc Kotlin pipeline (KotlinPoet formatters, Gradle tasks) to run
completely unchanged.

Pipeline:
  npm run tokens:fetch
    → fetch.ts: Figma Variables API → base.raw.android.json
                (same format as @skyscanner/bpk-foundations-android)
    → existing buildSrc Kotlin pipeline generates all token files

Tokens covered: semantic colors, spacing, radii, borders, typography
(font sizes, line heights, letter spacings, weights), elevation, animations.

No DTCG. No Style Dictionary. No changes to buildSrc. Node.js is only
needed for the fetch step, not for the token generation.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 3, 2026 12:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Introduces a simplified token-sync pipeline that fetches design tokens from the Figma Variables API and writes them directly into the existing bpk-foundations-android JSON format (no DTCG / Style Dictionary), keeping the current Kotlin/Gradle token generation flow unchanged.

Changes:

  • Adds token-sync/src/fetch.ts to fetch/transform Figma Variables into base.raw.android.json.
  • Adds a token-sync Node workspace (package.json) to run the fetch step via tsx.
  • Adds the generated token-sync/tokens/base.raw.android.json in the expected foundations format.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 5 comments.

File Description
token-sync/src/fetch.ts Implements Figma Variables API fetch + transformation into bpk-foundations-android JSON.
token-sync/package.json Adds Node scripts/deps to run the token fetch step.
token-sync/tokens/base.raw.android.json Adds generated output JSON consumed by the existing Kotlin pipeline.
Files not reviewed (1)
  • token-sync/package-lock.json: Generated file

Comment thread token-sync/src/fetch.ts
Comment on lines +113 to +121
const targetRaw = target.valuesByMode[primitivesModeId] ??
target.valuesByMode[Object.keys(target.valuesByMode)[0]];
if (!targetRaw || isFigmaAlias(targetRaw)) {
// Two-level alias — resolve further
if (isFigmaAlias(targetRaw)) {
return resolveValue(targetRaw, variables, primitivesModeId);
}
return null;
}
Comment thread token-sync/src/fetch.ts
Comment on lines +179 to +191
// Category mapping: Figma top-level group → bpk-foundations category + prop type
const PRIMITIVES_CATEGORY_MAP: Record<string, { category: string; type: BpkProp['type'] }> = {
'Spacing': { category: 'spacings', type: 'size' },
'Radius': { category: 'radii', type: 'size' },
'Border': { category: 'borders', type: 'size' },
'Heights': { category: 'spacings', type: 'size' },
'Modal': { category: 'spacings', type: 'size' },
'Type/Size': { category: 'typesettings', type: 'font-size' },
'Type/Line-height': { category: 'typesettings', type: 'size' },
'Type/Letter-spacing': { category: 'letter-spacings', type: 'letter-spacing' },
'Type/Weight': { category: 'font-weights', type: 'string' },
'Type/Family': { category: 'typesettings', type: 'font' },
};
Comment thread token-sync/src/fetch.ts
Comment on lines +316 to +327
// For letter-spacing, convert from px (Figma) to em ratio
// Figma stores letter-spacing in px; foundations uses em (relative to font size)
// We map tight/loose values directly
let value = light.value;
if (mapped.type === 'letter-spacing') {
const numVal = parseFloat(value);
if (!isNaN(numVal)) {
// Convert px offset to em: divide by a reference size of 16
const emVal = Math.round((numVal / 16) * 100) / 100;
value = String(emVal === 0 ? 0 : emVal);
}
}
Comment thread token-sync/src/fetch.ts
Comment on lines +347 to +351
const output: BpkFoundationsJson = {
aliases,
props,
propKeys: Object.keys(props),
};
Comment thread token-sync/package.json
Comment on lines +1 to +14
{
"name": "backpack-android-token-sync",
"version": "0.0.0",
"private": true,
"type": "module",
"scripts": {
"tokens:fetch": "tsx src/fetch.ts"
},
"devDependencies": {
"dotenv": "^16.4.7",
"tsx": "^4.19.2",
"typescript": "^5.7.3"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants