agentsclimarketplace

Cross platform token delivery

Skill almasumdev/awesome-mobile-design-system-agent-skills/.github/skills/platforms/cross-platform-token-delivery

Agent skills for building and maintaining mobile design systems, tokens, and component libraries.

Install
npx -y skills add almasumdev/awesome-mobile-design-system-agent-skills --skill cross-platform-token-delivery

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Delivering a single token set to Jetpack Compose, SwiftUI, Flutter, and React Native with type safety and no runtime cost. Use this when wiring the build output into consumer apps.

SKILL.md

7.3 KB, as published. Nobody here has run it

Cross-Platform Token Delivery

Instructions

The build output of Style Dictionary is not the end — it is the start. Tokens must arrive in each platform as idiomatic, type-safe, zero-runtime values that components consume without ceremony.

1. Delivery Contract

Every platform artifact must satisfy:

  • Type-safe: compiler catches typos (DsTokens.Color.Brand40, not a string).
  • Theme-aware: one import gives access to the current theme.
  • Zero runtime lookup cost: tokens resolved at composition / view-build time, not per frame.
  • Tree-shakeable: unused tokens do not inflate the binary (important for RN).

2. Compose / Kotlin

Ship a generated DsTokens object + a CompositionLocal-backed theme that exposes semantic tokens.

// generated: DsTokens.kt
object DsTokens {
    object Color {
        val Brand40 = Color(0xFF524173)
        val Neutral99 = Color(0xFFFFFBFF)
    }
    object Space { val Md: Dp = 16.dp }
}

// hand-written: Theme.kt
data class AppColors(
    val surfaceDefault: Color, val contentDefault: Color,
    val actionPrimaryBg: Color, val actionPrimaryFg: Color,
)

val LocalAppColors = staticCompositionLocalOf<AppColors> { error("AppColors not provided") }

object DsTheme {
    val colors: AppColors @Composable @ReadOnlyComposable get() = LocalAppColors.current
}

@Composable
fun AppTheme(dark: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
    val colors = if (dark) DarkAppColors else LightAppColors
    CompositionLocalProvider(LocalAppColors provides colors) {
        MaterialTheme(colorScheme = colors.toColorScheme()) { content() }
    }
}

Consumer:

Surface(color = DsTheme.colors.surfaceDefault) { /* ... */ }

3. SwiftUI / Swift

Ship a generated DSTokens enum plus EnvironmentKeys for the theme.

// generated
public enum DSTokens {
    public enum Color { public static let brand40 = SwiftUI.Color(hex: 0x524173) }
    public enum Space { public static let md: CGFloat = 16 }
}

// hand-written
public struct DSTheme {
    public var colors: DSColors
    public var spacing: DSSpacing
    public var motion:  DSMotion
    public static let light = DSTheme(colors: .light, spacing: .standard, motion: .standard)
    public static let dark  = DSTheme(colors: .dark,  spacing: .standard, motion: .standard)
}

private struct DSThemeKey: EnvironmentKey { static let defaultValue: DSTheme = .light }
public extension EnvironmentValues {
    var dsTheme: DSTheme { get { self[DSThemeKey.self] } set { self[DSThemeKey.self] = newValue } }
}

Consumer:

struct Banner: View {
    @Environment(\.dsTheme) var t
    var body: some View {
        Text("Hi").foregroundStyle(t.colors.contentDefault).padding(t.spacing.md)
    }
}

Color sets can also live in an .xcassets catalog (Color("surface/default")) — prefer that for colors because it gets Any/Dark appearance for free. Use the Swift enum for spacing, radii, motion.

4. Flutter / Dart

Use ThemeExtension<T> so tokens flow through Theme.of(context).

// generated
class DsTokens {
  static const Color brand40 = Color(0xFF524173);
  static const double spaceMd = 16;
}

// hand-written
class AppColors extends ThemeExtension<AppColors> {
  final Color surfaceDefault, contentDefault, actionPrimaryBg, actionPrimaryFg;
  const AppColors({required this.surfaceDefault, required this.contentDefault,
                   required this.actionPrimaryBg, required this.actionPrimaryFg});

  static const light = AppColors(
    surfaceDefault: Color(0xFFFFFBFF),
    contentDefault: Color(0xFF14101F),
    actionPrimaryBg: DsTokens.brand40,
    actionPrimaryFg: Color(0xFFFFFBFF),
  );
  static const dark = AppColors(/* ... */);

  @override AppColors copyWith({Color? surfaceDefault, /* ... */}) => AppColors(/* ... */);
  @override AppColors lerp(ThemeExtension<AppColors>? other, double t) => this;
}

ThemeData buildTheme({required bool dark}) => ThemeData(
    useMaterial3: true,
    colorScheme: dark ? darkColorScheme : lightColorScheme,
    extensions: [dark ? AppColors.dark : AppColors.light]);

Consumer:

final colors = Theme.of(context).extension<AppColors>()!;
Container(color: colors.surfaceDefault);

5. React Native / TypeScript

Ship a typed theme object and a ThemeProvider. Use useTheme() or a StyleSheet factory; avoid inline object creation in render.

// generated
export const tokens = {
  color: { brand40: '#524173', neutral99: '#FFFBFF' },
  space: { md: 16 },
} as const;
export type Tokens = typeof tokens;

// hand-written
export type Theme = {
  colors: { surfaceDefault: string; contentDefault: string;
            actionPrimaryBg: string; actionPrimaryFg: string };
  space:  typeof tokens.space;
};
export const lightTheme: Theme = { colors: { /* ... */ }, space: tokens.space };
export const darkTheme: Theme  = { colors: { /* ... */ }, space: tokens.space };

const ThemeCtx = createContext<Theme>(lightTheme);
export const ThemeProvider = ({ children }: { children: ReactNode }) => {
  const scheme = useColorScheme();
  const value = useMemo(() => (scheme === 'dark' ? darkTheme : lightTheme), [scheme]);
  return <ThemeCtx.Provider value={value}>{children}</ThemeCtx.Provider>;
};
export const useTheme = () => useContext(ThemeCtx);

Consumer:

const t = useTheme();
const styles = useMemo(() => StyleSheet.create({
  card: { backgroundColor: t.colors.surfaceDefault, padding: t.space.md },
}), [t]);

6. Distribution

Publish each platform artifact as a versioned package, same version across all four (see design-tokens-versioning):

  • Android: Maven Central (com.ds:ds-tokens:X.Y.Z).
  • iOS: Swift Package at https://github.com/org/ds-tokens-ios tagged vX.Y.Z.
  • Flutter: ds_tokens: ^X.Y.Z on pub.dev.
  • RN: @ds/[email protected] on the npm registry.

Consumer apps pin to caret ^X.Y.Z and upgrade via Renovate / Dependabot.

7. Cross-Platform Stories

Per component, produce the same rendered output on all four platforms for the same set of props. A CI job collects screenshots side-by-side into a review site. Parity is reviewed quarterly; drift files as a bug.

8. Anti-Patterns

  • Stringly-typed tokens (theme('colors.primary')).
  • Creating new theme objects per render (new Theme() in build).
  • Shipping raw hex via Style Dictionary directly into components without the semantic layer.
  • Mixing pre-compiled Compose tokens with a separate Kotlin color constants file.
  • RN StyleSheet.create({ color: theme.x }) inside render — breaks memoization; use factories.

Checklist

  • Each platform consumes tokens through an idiomatic theming channel (CompositionLocal / Environment / ThemeExtension / Context).
  • Reference values are generated; semantic tokens are hand-composed from them.
  • Theme objects are referentially stable — one instance per (theme × platform).
  • All platform packages are versioned at the same SemVer, published from one repo tag.
  • No component reads reference tokens directly; only semantic theme APIs.
  • A parity CI job renders per-component screenshots across all four platforms.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.