Context
The native iOS app (currently in App Store review) renders its native chrome — login screen, splash, error screens, toasts — with hardcoded colour, font-size, and radius values that drift from the design system. An Android app will follow. We want the theme package to be the single source of truth for those values, the same way it already is for web via the CSS/JS/Tailwind outputs.
Requirement
The build should emit tokens in native-consumable form alongside the existing outputs in lib/:
- Swift (
lib/theme-*.swift): a ThemeTokens enum of SwiftUI Color(red:green:blue:opacity:) and CGFloat constants
- Kotlin (
lib/theme-*.kt): the equivalent Compose Color(0xAARRGGBB) / Dp/TextUnit constants (needed when the Android app goes into development — can land later than Swift)
Token coverage
| Group |
Emit as |
Conversion |
color.* |
Color |
hsl()/hex → sRGB components at build time (SwiftUI has no HSL initialiser) |
size.font.* |
CGFloat (pt) |
rem × 16 — e.g. sm 0.875 → 14pt |
size.radii.* |
CGFloat (pt) |
rem × 16 — e.g. md 0.5 → 8pt |
size.space.* |
CGFloat (pt) |
rem × 16 |
size.leading.* |
CGFloat |
unitless line-height multipliers, emitted as-is |
Excluded, deliberately:
font.families.* — web font stacks (system-ui, -apple-system, …); the native apps bind their own bundled font by name
size.breakpoint.* — windowed-web concern, meaningless full-screen
effects.* — CSS box-shadow strings don't translate mechanically to native shadow parameters
Details
- Flat camelCase names from the token path, e.g.
color.blue.800 → blue800, color.subject.gcse-maths → subjectGcseMaths, size.font.sm → fontSm. These names become the native apps' API — renames are breaking.
- Alpha tokens (
color.alpha.*) carry their opacity component.
- Per-theme variants like the other formatters (
theme-base.swift, theme-atom.swift, …).
- No new packaging. The files ship inside the existing npm tarball (
files: ["lib"]); the native repos vendor the file for a pinned version (fetched from unpkg in their build). No Swift Package / Maven artifact needed.
- Tests: generated files contain no unconverted
hsl()/hex/rem values and no duplicate constant names.
Status
A working Swift formatter + vitest coverage already exists as a spike for the colour half (built from a local branch; the iOS repo currently vendors its output). Happy to open it as a PR to seed this — sizes are a small extension of the same formatter, and Kotlin follows the same pattern.
🤖 Generated with Claude Code
Context
The native iOS app (currently in App Store review) renders its native chrome — login screen, splash, error screens, toasts — with hardcoded colour, font-size, and radius values that drift from the design system. An Android app will follow. We want the theme package to be the single source of truth for those values, the same way it already is for web via the CSS/JS/Tailwind outputs.
Requirement
The build should emit tokens in native-consumable form alongside the existing outputs in
lib/:lib/theme-*.swift): aThemeTokensenum of SwiftUIColor(red:green:blue:opacity:)andCGFloatconstantslib/theme-*.kt): the equivalent ComposeColor(0xAARRGGBB)/Dp/TextUnitconstants (needed when the Android app goes into development — can land later than Swift)Token coverage
color.*Colorsize.font.*CGFloat(pt)sm0.875 → 14ptsize.radii.*CGFloat(pt)md0.5 → 8ptsize.space.*CGFloat(pt)size.leading.*CGFloatExcluded, deliberately:
font.families.*— web font stacks (system-ui, -apple-system, …); the native apps bind their own bundled font by namesize.breakpoint.*— windowed-web concern, meaningless full-screeneffects.*— CSS box-shadow strings don't translate mechanically to native shadow parametersDetails
color.blue.800→blue800,color.subject.gcse-maths→subjectGcseMaths,size.font.sm→fontSm. These names become the native apps' API — renames are breaking.color.alpha.*) carry their opacity component.theme-base.swift,theme-atom.swift, …).files: ["lib"]); the native repos vendor the file for a pinned version (fetched from unpkg in their build). No Swift Package / Maven artifact needed.hsl()/hex/rem values and no duplicate constant names.Status
A working Swift formatter + vitest coverage already exists as a spike for the colour half (built from a local branch; the iOS repo currently vendors its output). Happy to open it as a PR to seed this — sizes are a small extension of the same formatter, and Kotlin follows the same pattern.
🤖 Generated with Claude Code