# Figma To Landing Page

> Translates Figma design URLs into complete Nuxt 3 landing pages using RDS Vue UI components. Supports both Dev+ accounts (rich design context) and Basic accounts (screenshot-based). Use when user provides a Figma URL or screenshot of a design to implement.

- Skill: `chandima/figma-to-landing-page` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add chandima/figma-to-landing-page`
- Raw SKILL.md: https://api.skillmd.com/api/skills/chandima/figma-to-landing-page/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: chandima (https://skillmd.com/u/chandima)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/chandima/figma-to-landing-page

---


# Figma to Landing Page

## 1. Overview

Converts Figma designs into production-ready Nuxt 3 pages composed from `@rds-vue-ui/*` components. This skill implements a **two-tier approach** to accommodate different Figma account levels:

| Tier | Input | Context Quality | When Used |
|------|-------|-----------------|-----------|
| **Rich Path** (Dev+) | Figma URL | Full layout tree, typography, colors, component structure | `get_design_context` returns rich data |
| **Screenshot Path** (Basic) | Figma URL, prototype URL, or image | Visual analysis only | `get_design_context` fails, returns limited data, or user provides an image/screenshot |

Both tiers produce the same output: a `pages/<page-name>.vue` file with a companion `assets/content/<page-name>.json` data file, built entirely from `@rds-vue-ui/*` components.

---

## 2. Prerequisites

Before starting, confirm the following are available:

1. **Figma MCP server** — connected and responding (required for Figma URL inputs)
2. **Playwright MCP** — available for screenshot capture (required for prototype URLs and visual validation)
3. **`rds-component-mapper` skill** — must be available; it provides the shared component selection decision tree used by both tiers
4. **User input** — one of the following:
   - A Figma design URL (e.g. `https://figma.com/design/:fileKey/:fileName?node-id=1-2`)
   - A Figma prototype URL (e.g. `https://figma.com/proto/:fileKey/...`)
   - A screenshot or image file of the design

---

## 3. Step 1 — Detect Input Type & Account Tier

Determine which processing tier to use based on the input and available Figma access.

### 3.1 Parse the Input

1. **If Figma design URL** → extract `fileKey` and `nodeId` from the URL format:
   ```
   https://figma.com/design/:fileKey/:fileName?node-id=<nodeId>
   ```
   - `fileKey` is the path segment after `/design/`
   - `nodeId` is the `node-id` query parameter (e.g. `1-2`)

2. **If Figma prototype URL** → extract `fileKey` from:
   ```
   https://figma.com/proto/:fileKey/...
   ```
   - A prototype URL indicates the Screenshot Path (no design context available)

3. **If screenshot/image** → proceed directly to Screenshot Path (Step 2b)

### 3.2 Probe Account Tier

If a `fileKey` and `nodeId` were extracted:

1. Call `get_design_context(fileKey, nodeId)` via the Figma MCP server
2. Evaluate the response:
   - **Rich data returned** (layout tree, typography tokens, colors, component structure) → proceed to **Rich Path (Step 2a)**
   - **Call fails, times out, or returns limited/empty data** → fall back to **Screenshot Path (Step 2b)**

---

## 4. Step 2a — Rich Path (Dev+ Account)

Use this path when `get_design_context` returns comprehensive design data.

### 4.1 Extract Design Context

```
get_design_context(fileKey, nodeId)
```

From the response, extract:
- **Layout structure** — frame hierarchy, auto-layout direction, spacing, padding
- **Typography** — font family, size, weight, line height, letter spacing
- **Colors** — fills, strokes, effects (map to RDS theme CSS variables)
- **Component structure** — instances, variants, nested components

### 4.2 Get Visual Reference

```
get_screenshot(fileKey, nodeId)
```

Capture a screenshot for visual validation later.

### 4.3 Download Assets

Download any assets (icons, illustrations, images) from the Figma MCP localhost endpoints.

> **IMPORTANT:** Use the localhost URLs returned by the Figma MCP server directly. Do **NOT** import icon packages or substitute with icon libraries. The Figma assets are the source of truth for the design.

### 4.4 Handle Large / Truncated Responses

If `get_design_context` returns a response that is too large or appears truncated:

1. Call `get_metadata(fileKey, nodeId)` first to get the top-level structure
2. Identify child node IDs from the metadata
3. Fetch each child node individually with `get_design_context(fileKey, childNodeId)`
4. Reassemble the full design context from the individual responses

### 4.5 Map Sections to RDS Components

For each design section identified in the context:

1. **Invoke the `rds-component-mapper` skill decision tree** to select the best `@rds-vue-ui/*` component for the section's visual intent
2. **Map Figma design tokens to RDS component props:**
   - Figma auto-layout → RDS section layout props
   - Figma text styles → RDS typography props (heading level, size, weight)
   - Figma color fills → RDS theme CSS variables (`var(--rds-color-*)`)
   - Figma component instances → nested RDS sub-components
3. **Extract content:** headings, body text, CTA labels, image URLs, link targets
4. **Extract colors:** map hex values to the closest RDS theme variable

### 4.6 Compose the Page

Assemble all mapped sections into a single `pages/<page-name>.vue` file:

```vue
<script setup>
const content = await import('~/assets/content/<page-name>.json')
</script>

<template>
  <div>
    <!-- Each section maps to an @rds-vue-ui/* component -->
    <HeroStandardApollo v-bind="content.hero" />
    <SectionCardsApollo v-bind="content.cards" />
    <!-- ... -->
  </div>
</template>
```

### 4.7 Create Content JSON

Create `assets/content/<page-name>.json` with all extracted content:

```json
{
  "hero": {
    "heading": "Extracted heading from Figma",
    "subheading": "Extracted subheading",
    "ctaLabel": "Get Started",
    "ctaUrl": "#",
    "backgroundImage": "/images/hero-bg.jpg"
  },
  "cards": {
    "items": [
      {
        "title": "Card Title",
        "description": "Card description text",
        "image": "/images/card-1.jpg"
      }
    ]
  }
}
```

### 4.8 Validate Against Screenshot

Compare the composed page output against the Figma screenshot captured in Step 4.2. Check alignment, spacing, typography, and color fidelity.

---

## 5. Step 2b — Screenshot Path (Basic Account / Image Input)

Use this path when rich design context is unavailable.

### 5.1 Obtain the Screenshot

| Input Type | Method |
|------------|--------|
| Figma design URL | Call `get_screenshot(fileKey, nodeId)` — works on all Figma account tiers |
| Figma prototype URL | Use Playwright MCP: `browser_navigate` to the URL, then `browser_take_screenshot` |
| User-provided image | Use the image directly |

### 5.2 Analyze the Screenshot

Use the vision model to analyze the screenshot and identify:

1. **Page sections** — hero area, content blocks, testimonial strips, card grids, CTAs, footer
2. **Approximate layout** — full-width sections, grid columns (2-col, 3-col, 4-col), sidebars, stacked layouts
3. **Content** — headings (H1, H2, H3), body text, button labels, image placeholders
4. **Color palette** — dominant colors, accent colors, background tones
5. **Typography hints** — relative font sizes, weight variations (bold headings vs. regular body), text alignment

### 5.3 Map Sections to RDS Components

For each visually identified section:

1. **Invoke the `rds-component-mapper` skill decision tree** to select the closest `@rds-vue-ui/*` component
2. **Infer props from visual analysis:**
   - Section height/width → layout sizing props
   - Observed colors → closest RDS theme CSS variables
   - Text content → extract where readable, use descriptive placeholders where not (e.g. `"[Hero heading text]"`)
   - Image areas → placeholder image paths
3. **Generate placeholder content** for any text that cannot be reliably extracted from the screenshot

### 5.4 Compose the Page

Assemble into `pages/<page-name>.vue` following the same structure as the Rich Path (Step 4.6).

### 5.5 Create Content JSON

Create `assets/content/<page-name>.json` following the same structure as the Rich Path (Step 4.7). Mark placeholder content clearly:

```json
{
  "hero": {
    "heading": "[Hero heading — replace with actual copy]",
    "subheading": "[Subheading — replace with actual copy]",
    "ctaLabel": "Learn More",
    "backgroundImage": "/images/placeholder-hero.jpg"
  }
}
```

### 5.6 Visual Comparison

1. Take a screenshot of the generated page using Playwright MCP (`browser_navigate` → `browser_take_screenshot`)
2. Compare side-by-side with the original Figma screenshot / user image
3. Iterate on component selection and props until the output closely matches the original design

---

## 6. Translation Rules

Figma MCP outputs React + Tailwind CSS by default. All output must be translated to the RDS stack:

| Figma MCP Output | RDS Target |
|-------------------|------------|
| React JSX | Vue 3 `<template>` with `<script setup>` |
| Tailwind utility classes | Bootstrap 5 classes or custom SCSS |
| Inline `style` objects | SCSS `<style lang="scss" scoped>` blocks |
| Hardcoded hex colors | RDS theme CSS variables (`var(--rds-primary)`, `var(--rds-secondary)`, etc.) |
| `className` | `class` |
| `onClick` / `onChange` | `@click` / `@change` |
| `{condition && <El/>}` | `v-if="condition"` |
| `{items.map(i => ...)}` | `v-for="item in items"` |
| React component imports | **None** — RDS components are auto-imported via Nuxt component scanner |

### Component Naming

- Use **PascalCase** for all component names in templates: `<HeroStandardApollo>`, `<SectionCardsApollo>`
- Do **NOT** add `import` statements for `@rds-vue-ui/*` components — they are auto-imported

### Styling

- Use Bootstrap 5 utility classes where they match the design intent
- For custom styling beyond Bootstrap, use scoped SCSS:
  ```vue
  <style lang="scss" scoped>
  .custom-section {
    padding: 4rem 0;
    background-color: var(--rds-surface);
  }
  </style>
  ```
- Never use Tailwind classes — the project uses Bootstrap 5 + SCSS exclusively

---

## 7. Desktop + Mobile

### When Both Viewports Are Provided

If the user provides separate Figma nodes for desktop and mobile:

1. Extract/analyze both viewports
2. Implement responsive behavior using Bootstrap responsive classes:
   - `col-lg-*` / `col-md-*` / `col-sm-*` for grid columns
   - `d-none d-lg-block` / `d-lg-none` for viewport-specific elements
   - `order-lg-*` for reordering on different breakpoints
3. Validate both viewports against their respective Figma screenshots

### When Only Desktop Is Provided

1. Implement the desktop design faithfully
2. Apply sensible mobile defaults using Bootstrap's responsive grid
3. Stack columns on mobile (`col-12` on small screens, `col-lg-*` on large)

### Breakpoint Reference

| Bootstrap Class | Breakpoint |
|----------------|------------|
| `col-sm-*` | ≥ 576px |
| `col-md-*` | ≥ 768px |
| `col-lg-*` | ≥ 992px |
| `col-xl-*` | ≥ 1200px |
| `col-xxl-*` | ≥ 1400px |

---

## 8. Validation Checklist

Before considering the page complete, verify every item:

- [ ] **Layout matches** — spacing, alignment, sizing match the Figma design
- [ ] **Typography matches** — font family, size, weight, line height are correct
- [ ] **Colors match** — all colors use RDS theme CSS variables (no hardcoded hex)
- [ ] **Components used** — all sections use `@rds-vue-ui/*` components where a suitable match exists
- [ ] **Content is JSON-driven** — all text, images, and data come from `assets/content/<page-name>.json`
- [ ] **No manual imports** — no `import` statements for RDS components (auto-imported)
- [ ] **Vue 3 syntax** — `<script setup>`, `v-if`, `v-for`, `@click` (no React patterns)
- [ ] **Bootstrap 5 only** — no Tailwind classes; Bootstrap utilities + SCSS
- [ ] **Responsive** — desktop and mobile viewports render correctly
- [ ] **Assets downloaded** — icons and images from Figma are saved locally (not imported from packages)
- [ ] **Visual comparison** — side-by-side screenshot matches the original design

---

## 9. Examples

### Example 1: Figma URL with Dev+ Account (Rich Path)

**User input:**
```
Build a landing page from this Figma design:
https://figma.com/design/ABC123xyz/campaign-summer-2025?node-id=1-2
```

**Agent workflow:**

1. Parse URL → `fileKey = "ABC123xyz"`, `nodeId = "1-2"`
2. Call `get_design_context("ABC123xyz", "1-2")` → returns rich data:
   ```
   Frame "Hero Section"
     - Auto-layout: vertical, gap 24px, padding 64px
     - Background: linear-gradient(#1a2b3c, #2c3d4e)
     - Text "Summer Campaign 2025" — Inter Bold 48px #FFFFFF
     - Text "Discover what's new" — Inter Regular 18px #B0B8C4
     - Button "Explore Now" — fill #FF6B35, text #FFFFFF
   Frame "Features Grid"
     - Auto-layout: horizontal, gap 32px, wrap
     - 3x Card children with icon + title + description
   Frame "Testimonials"
     - Carousel with 4 testimonial cards
   ```
3. Call `get_screenshot("ABC123xyz", "1-2")` → save reference image
4. Download icon assets from Figma MCP localhost URLs
5. Invoke `rds-component-mapper` for each section:
   - "Hero Section" → `HeroStandardApollo`
   - "Features Grid" → `SectionCardsApollo`
   - "Testimonials" → `SectionTestimonialsApollo`
6. Map Figma tokens to RDS props:
   - `#1a2b3c` gradient → `var(--rds-primary-dark)`
   - `#FF6B35` button → `var(--rds-accent)`
   - Inter Bold 48px → heading level 1
7. Create `pages/campaign-summer-2025.vue`:
   ```vue
   <script setup>
   import content from '~/assets/content/campaign-summer-2025.json'
   </script>

   <template>
     <div>
       <HeroStandardApollo
         :heading="content.hero.heading"
         :subheading="content.hero.subheading"
         :cta-label="content.hero.ctaLabel"
         :cta-url="content.hero.ctaUrl"
         :background-image="content.hero.backgroundImage"
       />
       <SectionCardsApollo
         :heading="content.features.heading"
         :cards="content.features.items"
       />
       <SectionTestimonialsApollo
         :testimonials="content.testimonials.items"
       />
     </div>
   </template>
   ```
8. Create `assets/content/campaign-summer-2025.json` with all extracted text, images, and links
9. Validate: compare rendered page screenshot against Figma screenshot

---

### Example 2: User Provides a Screenshot (Screenshot Path)

**User input:**
```
Here's a screenshot of the design I need built:
[attached: design-mockup.png]
```

**Agent workflow:**

1. No Figma URL → proceed to Screenshot Path
2. Analyze `design-mockup.png` with vision model:
   ```
   Identified sections:
   - Hero: full-width, dark background, large white heading, subtitle, orange CTA button
   - Stats bar: horizontal row of 4 stat counters with numbers and labels
   - Cards: 3-column grid, each card has an icon, heading, and paragraph
   - CTA banner: accent-colored background, centered heading, two buttons
   - Footer: dark background, 4-column links layout, social icons
   ```
3. Invoke `rds-component-mapper` for each section:
   - Hero → `HeroStandardApollo`
   - Stats bar → `SectionCountersApollo`
   - Cards grid → `SectionCardsApollo`
   - CTA banner → `SectionCtaApollo`
   - Footer → `FooterStandardApollo`
4. Infer props from visual analysis:
   - Dark hero background → `var(--rds-primary-dark)`
   - Orange CTA → `var(--rds-accent)`
   - 3-column layout → `columns: 3`
5. Create `pages/design-mockup.vue`:
   ```vue
   <script setup>
   import content from '~/assets/content/design-mockup.json'
   </script>

   <template>
     <div>
       <HeroStandardApollo
         :heading="content.hero.heading"
         :subheading="content.hero.subheading"
         :cta-label="content.hero.ctaLabel"
         :cta-url="content.hero.ctaUrl"
       />
       <SectionCountersApollo
         :counters="content.stats.items"
       />
       <SectionCardsApollo
         :heading="content.cards.heading"
         :cards="content.cards.items"
         :columns="3"
       />
       <SectionCtaApollo
         :heading="content.cta.heading"
         :primary-label="content.cta.primaryLabel"
         :secondary-label="content.cta.secondaryLabel"
       />
       <FooterStandardApollo
         :columns="content.footer.columns"
         :social-links="content.footer.socialLinks"
       />
     </div>
   </template>
   ```
6. Create `assets/content/design-mockup.json` with placeholder content:
   ```json
   {
     "hero": {
       "heading": "[Hero heading — replace with actual copy]",
       "subheading": "[Subheading — replace with actual copy]",
       "ctaLabel": "Get Started",
       "ctaUrl": "#"
     }
   }
   ```
7. Take screenshot of rendered page via Playwright MCP
8. Compare side-by-side with original `design-mockup.png`
9. Iterate: adjust component props and layout until visual match is satisfactory

