Token Architecture
Three layers: primitives → foundation → semantic/component. Never reach past the semantic layer in component code.
Layer Diagram
0
Layer 0 — Primitives
tokens/baseColors.js · Downloads/BASE COLOR.json
Raw swatches with no semantic meaning. Named by color family and shade. Never reference these directly in component code.
poliPurple.500 → #6a35ff
popBlack.400 → #121212
orangeSunshine.500 → #ff8744
parkGreen.500 → #3bffad
error.500 → #ee4d37
↓
1
Layer 1 — Foundation
tokens/colors.js · Downloads/tokensModularApp.json (fyscalFoundation)
Semantic naming with light/dark mode values. These alias primitives. Two collections: fyscalFoundation (light/dark pairs) and neon (fixed dark palette variant).
Main/Primary → light:#352eff dark:#a1ff5b
Main/Black → light:#171717 dark:#ffffff
Mono/900 → light:#191919 dark:#e5e5e5
System/Danger → #ff0000 (both)
Tint/Primary/100 → #eaeaff
↓
2
Layer 2 — Semantic + Component
tokens/colorTokens.js · Downloads/tokensModularApp.json (fyscalToken)
Component-scoped tokens with exact Figma variable names. Aliases resolved through layer 1. Token names use
/ separators verbatim — never normalise to hyphens. Intentional typos match Figma exactly.
btn/primary/default → #352eff
input-field/focus/outline-box → #352eff
devider/default → #efefef ⚠ typo
alert/waring/text-warning → #ff8400 ⚠ typo
main-text/inverterd → #fff ⚠ typo
OTP/focus/outline-box → #352eff
⚠ Intentional Figma Typos — Match Exactly
devider
— should be "divider"
waring
— should be "warning"
inverterd
— should be "inverted"
Token Namespaces (Layer 2)
background
Page/surface backgrounds
background/bg-default
background/bg-secondary
background/bg-tertiary
main-text
Text colors
main-text/default
main-text/description
main-text/brand
main-text/placeholder
main-text/disabled
main-text/inverterd ⚠
btn
All button types
btn/primary/*
btn/secondary/*
btn/textonly/*
btn/sliding/*
btn/swipeup/*
input-field
Input states
input-field/default/*
input-field/active/*
input-field/focus/*
input-field/error/*
input-field/disabled/*
OTP
OTP boxless variant
OTP/default/*
OTP/focus/*
OTP/active/*
OTP/disabled/*
alert
Alert types
alert/primary/*
alert/waring/* ⚠
alert/success/*
alert/danger/*
badge & chip
Badges and chips
badge & chip/primary/*
badge & chip/white/*
badge & chip/waring/* ⚠
badge & chip/success/*
badge & chip/danger/*
nav bar
Navigation components
nav bar/bg-primary
nav bar/bg-secondary
nav bar/active-state
nav bar/icon-default
nav bar/text-default
bubble / balance / gain&loss
Finance + chat
bubble/bg-incoming
bubble/bg-outcoming
Balance/Bg
gain&loss/success/*
gain&loss/danger/*
Three Codebases — Don't Cross-Pollinate
React Native
design-system/
design-system/
Styling: StyleSheet.create()
Fonts: useFonts() hook
Spacing: usePadding() hook
Images: react-native-fast-image
Animations: lottie-react-native
Icons: react-native-svg
⚠ Never use CSS here. Hooks at module level will crash.
React Web + MUI
kelly-web/
kelly-web/
Styling: MUI sx prop + Emotion
Theme: createTheme() + ThemeProvider
Global: SCSS modules
State: Redux Toolkit + RxJS
Font: Plus Jakarta Sans via CDN
⚠ Don't add CSS custom properties here — use MUI palette tokens.
Standalone OTP
OTPInput.tsx + .css
OTPInput.tsx + .css
Styling: CSS custom properties
Token names: Figma verbatim with /
Build: Vite 5
OTP slots: 48×48px (fixed)
Focus ring: rgba(53,46,255,0.4)
⚠ Never hardcode hex — always use a token. Focus ring never changes in dark mode.