Skip to content

05 -- Extract Theme Tokens from Figma

Prompt Template — Savoy Signature Hotels
Use when: A new hotel brand needs its design tokens extracted from Figma and implemented as a CSS theme file.


Before using this prompt, read the following files so you have full project context:

packages/themes/src/_base.css # Shared tokens (spacing, typography scale, radii, shadows, z-index)
packages/themes/src/{SITE_KEY}.css # Existing theme file (if updating) or a sibling theme for reference
packages/themes/src/index.css # Theme index -- imports _base + all theme files
docs/dev-frontend-guides/02_DESIGN_TOKENS_EXTRACTION.md # Full extraction process and token naming
docs/PRD/05_Design_System_and_Theming.md # Design system specification
apps/web/src/lib/fonts.ts # Font registration with next/font

I need to extract design tokens from a Figma style guide and create a CSS theme file for a Savoy hotel.
**Hotel:** {HOTEL_NAME}
**Site key:** {SITE_KEY}
**Figma URL:** {FIGMA_URL}
### Color Palette
| Role | Hex Value |
|-----------------------|-----------------|
| Primary | {COLOR_PRIMARY} |
| Primary Light | {COLOR_PRIMARY_LIGHT} |
| Primary Dark | {COLOR_PRIMARY_DARK} |
| Secondary | {COLOR_SECONDARY} |
| Secondary Light | {COLOR_SECONDARY_LIGHT} |
| Secondary Dark | {COLOR_SECONDARY_DARK} |
| Accent | {COLOR_ACCENT} |
| Background | {COLOR_BG} |
| Background Alt | {COLOR_BG_ALT} |
| Background Dark | {COLOR_BG_DARK} |
| Surface | {COLOR_SURFACE} |
| Text | {COLOR_TEXT} |
| Text Muted | {COLOR_TEXT_MUTED} |
| Text Inverse | {COLOR_TEXT_INVERSE} |
| Text on Primary | {COLOR_TEXT_ON_PRIMARY} |
| Text on Secondary | {COLOR_TEXT_ON_SECONDARY} |
| Border | {COLOR_BORDER} |
| Border Strong | {COLOR_BORDER_STRONG} |
| Success | {COLOR_SUCCESS} |
| Warning | {COLOR_WARNING} |
| Error | {COLOR_ERROR} |
### Typography
| Role | Family | Weights |
|---------------|-------------------------|-------------------|
| Heading font | {FONT_HEADING_FAMILY} | {FONT_HEADING_WEIGHTS} |
| Body font | {FONT_BODY_FAMILY} | {FONT_BODY_WEIGHTS} |
| Accent font | {FONT_ACCENT_FAMILY} | {FONT_ACCENT_WEIGHTS} |
### Shadows (if different from _base.css)
| Token | Value |
|--------------|---------------------|
| --shadow-sm | {SHADOW_SM} |
| --shadow-md | {SHADOW_MD} |
| --shadow-lg | {SHADOW_LG} |
### Overrides vs Base
{OVERRIDE_NOTES}
(Describe any tokens where this theme diverges from _base.css defaults -- e.g., different radii, custom spacing, unique transition speeds.)
### Tasks
1. Create `packages/themes/src/{SITE_KEY}.css` with all tokens under `[data-theme="{SITE_KEY}"]`.
2. Add the import to `packages/themes/src/index.css`.
3. Register the heading, body, and accent fonts in `apps/web/src/lib/fonts.ts` using `next/font/google` with `display: 'swap'`.
4. Add the new theme to the Storybook theme switcher so all components can be previewed with it.
5. Verify color contrast: all text/background pairs must meet WCAG 2.1 AA (4.5:1 for normal text, 3:1 for large text).

  • New file packages/themes/src/{SITE_KEY}.css exists with [data-theme="{SITE_KEY}"] selector
  • All color tokens are defined: --color-primary, --color-primary-light, --color-primary-dark, --color-secondary, --color-secondary-light, --color-secondary-dark, --color-accent, --color-bg, --color-bg-alt, --color-bg-dark, --color-surface, --color-text, --color-text-muted, --color-text-inverse, --color-text-on-primary, --color-text-on-secondary, --color-border, --color-border-strong, --color-success, --color-warning, --color-error
  • Typography tokens are defined: --font-heading, --font-body, --font-accent, --font-weight-normal, --font-weight-medium, --font-weight-semibold, --font-weight-bold
  • Shadow tokens are defined if they differ from _base.css
  • Theme file is imported in packages/themes/src/index.css
  • Fonts registered in apps/web/src/lib/fonts.ts with subsets: ['latin'] and display: 'swap'
  • Storybook theme switcher includes the new theme
  • All existing components render correctly under the new theme in Storybook
  • Color contrast verified: text on --color-bg >= 4.5:1, text on --color-primary >= 4.5:1, text on --color-surface >= 4.5:1
  • Theme CSS file is under 5KB gzipped
  • No hardcoded color or font values anywhere — all values use CSS custom properties

PitfallHow to Avoid
Forgetting --color-text-on-primary or --color-text-on-secondaryAlways define text-on-* tokens so buttons and badges remain readable on brand backgrounds
Using rgba() with hardcoded colors instead of token references in shadowsShadow tokens should use the theme’s primary color for tinted shadows, e.g., rgba(26, 54, 93, 0.08) matching --color-primary
Not registering fonts in fonts.tsFonts must be loaded via next/font to avoid layout shift and FOUT — a CSS @import alone is not sufficient
Mismatching the data-theme value and the site keyThe data-theme attribute value must exactly match the site key used in routing and configuration (lowercase, hyphenated)
Skipping the import in index.cssThe theme file will have no effect if it is not imported in the index
Defining tokens already covered by _base.css unnecessarilyOnly override base tokens when the theme genuinely differs — spacing, radii, z-index, and transitions are shared unless the brand requires a deviation
Insufficient contrast on dark backgrounds--color-bg-dark with --color-text-inverse must be checked separately from the light palette

Context files read:

packages/themes/src/_base.css
packages/themes/src/saccharum.css # Existing stub to expand
packages/themes/src/savoy-palace.css # Reference for a complete theme
docs/dev-frontend-guides/02_DESIGN_TOKENS_EXTRACTION.md
docs/PRD/05_Design_System_and_Theming.md

Filled-in prompt:

I need to extract design tokens from a Figma style guide and create a CSS theme file for a Savoy hotel.
**Hotel:** Saccharum Resort
**Site key:** saccharum
**Figma URL:** https://www.figma.com/file/abc123/Saccharum-Style-Guide
### Color Palette
| Role | Hex Value |
|-----------------------|-------------|
| Primary | #234e52 |
| Primary Light | #2d6a6e |
| Primary Dark | #1a3c3f |
| Secondary | #c5a55a |
| Secondary Light | #d4bc7e |
| Secondary Dark | #a88b3d |
| Accent | #e8dcc8 |
| Background | #faf8f5 |
| Background Alt | #f0ece4 |
| Background Dark | #1a1a1a |
| Surface | #ffffff |
| Text | #1a202c |
| Text Muted | #6b7280 |
| Text Inverse | #ffffff |
| Text on Primary | #ffffff |
| Text on Secondary | #1a202c |
| Border | #e2ded6 |
| Border Strong | #c9c4b8 |
| Success | #38a169 |
| Warning | #d69e2e |
| Error | #e53e3e |
### Typography
| Role | Family | Weights |
|---------------|-------------------------|---------------|
| Heading font | Playfair Display, serif | 400, 700 |
| Body font | Inter, sans-serif | 400, 500, 600 |
| Accent font | Cormorant Garamond, serif | 400, 600 |
### Shadows
| Token | Value |
|--------------|-----------------------------------------|
| --shadow-sm | 0 1px 2px rgba(35, 78, 82, 0.05) |
| --shadow-md | 0 4px 12px rgba(35, 78, 82, 0.08) |
| --shadow-lg | 0 8px 24px rgba(35, 78, 82, 0.12) |
### Overrides vs Base
No overrides to base tokens needed. Saccharum uses the standard spacing scale,
border radii, z-index, and transition values from _base.css.
### Tasks
1. Create `packages/themes/src/saccharum.css` with all tokens under `[data-theme="saccharum"]`.
2. Add the import to `packages/themes/src/index.css`.
3. Register Playfair Display, Inter, and Cormorant Garamond in `apps/web/src/lib/fonts.ts`.
4. Add "saccharum" to the Storybook theme switcher.
5. Verify color contrast: #1a202c on #faf8f5, #ffffff on #234e52, #1a202c on #c5a55a.

Expected output: A complete saccharum.css file with 21 color tokens, 7 typography tokens, and 3 shadow tokens, all scoped under [data-theme="saccharum"]. Fonts registered in fonts.ts with next/font/google. Storybook updated to include the Saccharum theme in its switcher.