reference-to-landing-page

Installation
SKILL.md

Reference-to-Landing-Page

1. Overview

This skill takes a reference website URL plus a user modification prompt and produces a complete Nuxt 3 landing page built entirely with @rds-vue-ui/* components. It uses Playwright MCP for browser automation to capture the reference page, then translates every section into the RDS design system.

Inputs:

  • A URL to an existing web page (the "reference")
  • Natural-language instructions describing how the new page should differ

Outputs:

  • pages/<page-name>.vue — the composed landing page
  • assets/content/<page-name>.json — JSON-driven content for the page
  • Screenshots of both reference and final page for visual comparison

2. Prerequisites

Before executing this skill, verify:

  1. Playwright MCP server is connected (@playwright/mcp@latest). Test with browser_navigate.
  2. rds-component-mapper skill is available — it is required for Step 4 (component selection).
  3. User has provided:
    • A reference URL (must be publicly accessible or accessible from the current network)
    • Natural-language description of desired modifications
  4. Project context: You are working inside a Nuxt 3 project scaffolded from the rds-lp-factory template with @rds-vue-ui/* packages available.

3. Workflow

Execute these steps in order. Do not skip steps.

Step 1: Capture the Reference Page

Use Playwright MCP tools to fully capture the reference page:

1. browser_navigate({ url: "<reference-url>" })
2. Wait for page to fully load (network idle)
3. browser_take_screenshot({ fullPage: true })
   → Save/note this as "reference screenshot"
4. browser_snapshot()
   → This returns the accessibility tree — the primary structural data

For long pages (common with landing pages):

5. browser_execute_javascript({ script: "document.body.scrollHeight" })
   → Get total page height
6. If height > 3000px, scroll in increments and capture additional screenshots:
   - browser_execute_javascript({ script: "window.scrollTo(0, 1500)" })
   - browser_take_screenshot()
   - Repeat until entire page is captured
7. browser_snapshot() again after scrolling to ensure all lazy-loaded content is captured

What to extract from the accessibility tree:

  • Document title and meta description
  • Navigation structure (links, dropdowns)
  • All text content (headings, paragraphs, list items)
  • Image alt text and approximate placement
  • Link targets and button labels
  • Form fields and their labels
  • ARIA landmarks (banner, main, contentinfo, navigation)

Step 2: Analyze Page Structure

Parse the accessibility snapshot into a section inventory. Identify each distinct section of the page and classify it:

Section Type What to Look For
Navigation <nav> landmark, logo, menu links, CTA button
Hero/Banner First large section, prominent heading (h1), background image, CTA
Introduction Short text block after hero, often with subheading
Features/Benefits Grid of items with icons/images + short text, often 3-4 columns
Card Grid Repeated card-like structures with image + title + description
Testimonials Quotes with attribution, photos, star ratings
Statistics/Numbers Large numbers with labels (e.g., "500+ students")
Video Section Embedded video or play button with thumbnail
Parallax/Full-width Image Full-width background image with overlaid text
Call to Action Prominent button/form section urging user action
Form Section Input fields, labels, submit button
FAQ/Accordion Question-answer pairs, expandable items
Footer Contact info, social links, copyright, secondary nav

For each identified section, record:

- section_index: 1
  type: hero
  purpose: "Primary hero with program headline and apply CTA"
  content:
    heading: "Welcome to the MBA Program"
    subheading: "Transform your career..."
    cta_text: "Apply Now"
    cta_url: "/apply"
    background_image: true
  layout: full-width, centered text
  approximate_style: "dark overlay on image, white text, large heading"

Step 3: Apply User's Modification Intent

Parse the user's natural-language prompt and categorize the requested changes:

Change Category Examples How to Apply
Content swap "Make it for basketball instead of baseball" Replace all program-specific text, images, links
Branding change "Use maroon and gold colors" Update color variables, theme selection
Section addition "Add a video hero section" Insert new section in appropriate position
Section removal "Remove the contact form" Delete section from inventory
Section reorder "Put testimonials before features" Rearrange section order
Layout change "Make the cards 2 columns instead of 3" Adjust grid configuration
CTA change "Change apply button to schedule a visit" Update CTA text, URL, styling
Tone/audience "Make it more casual and student-focused" Rewrite copy with new tone

Produce a modified section inventory that reflects all user changes applied to the original structure.


Step 4: Map to RDS Components

For every section in the modified inventory, select the appropriate @rds-vue-ui/* component.

IMPORTANT: Invoke the rds-component-mapper skill for component selection. Do not guess component names — use the decision tree from that skill.

Mapping process for each section:

1. Take the section type + purpose from Step 2/3
2. Match against the rds-component-mapper decision tree:
   - Hero → HeroStandardApollo | HeroVideoApollo | HeroArticleAtlas
   - Card grid → SectionCardApollo | SectionCardAtlas + CardIcon | CardImageArticle | etc.
   - Testimonials → SectionTestimonialFalcon | SectionTestimonialAtlas | etc.
   - Video → SectionVideoApollo | SectionVideoModal
   - Parallax → SectionParallaxApollo | SectionParallaxAtlas
   - FAQ → RdsAccordion | OverlapAccordionAtlas
   - Footer → FooterDefault | FooterPartner
   - Navigation → NavbarDefault | NavbarSticky
   - Forms → RdsInput, RdsCheckbox, RdsDropdown, etc.
3. Record: component name, package name, required props, slot content

Component selection constraints:

  • Every visible section MUST use an RDS component — no raw HTML sections
  • If no exact match exists, use the closest container (SectionApollo, SectionContainerAtlas) and compose with smaller RDS components inside
  • Cards inside card sections must also be RDS card components
  • Bootstrap 5 grid (container, row, col-*) is allowed for custom layout within sections

Step 5: Compose the Landing Page

5a. Create the content JSON file

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

{
  "meta": {
    "title": "Page Title",
    "description": "Meta description for SEO"
  },
  "hero": {
    "heading": "Main Headline",
    "subheading": "Supporting text...",
    "ctaText": "Apply Now",
    "ctaUrl": "/apply",
    "backgroundImage": "/images/hero-bg.jpg"
  },
  "features": {
    "heading": "Why Choose Us",
    "items": [
      {
        "icon": "fa-star",
        "title": "Feature One",
        "description": "Description text..."
      }
    ]
  },
  "testimonials": {
    "heading": "Student Stories",
    "items": [
      {
        "quote": "This program changed my life...",
        "name": "Jane Doe",
        "title": "Class of 2024",
        "image": "/images/testimonial-1.jpg"
      }
    ]
  }
}

5b. Create the page component

Create pages/<page-name>.vue:

<template>
  <div>
    <!-- Navigation -->
    <NavbarDefault v-bind="navbarProps" />

    <!-- Hero Section -->
    <HeroStandardApollo v-bind="heroProps">
      <template #content>
        <h1>{{ content.hero.heading }}</h1>
        <p>{{ content.hero.subheading }}</p>
        <a :href="content.hero.ctaUrl" class="btn btn-primary">
          {{ content.hero.ctaText }}
        </a>
      </template>
    </HeroStandardApollo>

    <!-- Features Section -->
    <SectionCardApollo v-bind="featuresProps">
      <template #cards>
        <CardIcon
          v-for="(item, index) in content.features.items"
          :key="index"
          v-bind="mapFeatureToCardProps(item)"
        />
      </template>
    </SectionCardApollo>

    <!-- Additional sections... -->

    <!-- Footer -->
    <FooterDefault v-bind="footerProps" />
  </div>
</template>

<script setup>
import content from '~/assets/content/<page-name>.json'

// Map content to component props
const heroProps = computed(() => ({
  // ... map from content.hero
}))
</script>

<style lang="scss" scoped>
// Use RDS theme variables for any custom styling
// @use '~/assets/scss/variables' as *;
</style>

Composition rules:

  • Use <script setup> with Composition API
  • All RDS components are auto-imported — do NOT add import statements for them
  • Content comes from JSON file, imported at the top of <script setup>
  • Use computed() to map JSON content to component props
  • Use Bootstrap 5 grid classes for layout adjustments
  • Use SCSS with RDS theme variables for any custom styling
  • Sections are composed vertically in the <template>, one after another

Step 6: Visual Validation

If a dev server is running (or can be started):

1. browser_navigate({ url: "http://localhost:3000/<page-name>" })
2. Wait for page to fully render
3. browser_take_screenshot({ fullPage: true })
   → Save as "output screenshot"
4. Compare visually with the reference screenshot from Step 1
5. Check for:
   - Missing sections (compare section count)
   - Broken layout (overlapping elements, misaligned grids)
   - Missing content (text, images, links)
   - Spacing inconsistencies (too cramped or too spread out)
   - Color/theme mismatches
6. Fix any issues found and re-screenshot until satisfactory

If no dev server is available, perform a code review instead:

  • Verify every section from the modified inventory is present in the template
  • Verify all content JSON keys are referenced in the template
  • Verify component props match the rds-component-mapper documentation
  • Verify no raw HTML is used where an RDS component exists

4. Translation Rules

These rules are mandatory and must not be violated:

  1. Never copy source code from the reference page. The reference is visual inspiration only — all code must be freshly written using @rds-vue-ui/* components.

  2. Every section uses an RDS component. If the reference has a custom HTML section, find the closest RDS component match. Use SectionApollo or SectionContainerAtlas as generic wrappers when needed.

  3. Content is JSON-driven. All text, image URLs, links, and configuration live in the content JSON file, not hardcoded in the template.

  4. Components are auto-imported. Never write import { HeroStandardApollo } from '...' — the Nuxt component scanner handles this.

  5. Use Bootstrap 5 grid for custom layout needs within sections. Do not use CSS Grid or Flexbox utilities directly when Bootstrap classes suffice.

  6. Style with SCSS using RDS theme variables. Do not use inline styles or Tailwind-like utility classes.

  7. Respect the user's modifications. The final page must reflect ALL changes the user requested, not just a copy of the reference.

  8. Preserve accessibility. Use semantic HTML, proper heading hierarchy (h1 → h2 → h3), alt text on images, and ARIA labels where needed.


5. Examples

Example 1: Content Swap

User prompt: "Take mlb.asu.edu and make a version for the ASU basketball program"

Process:

  1. Capture mlb.asu.edu — hero, program highlights, faculty cards, testimonials, CTA
  2. Structure: Hero → Intro → Card Grid (programs) → Testimonials → CTA → Footer
  3. Modifications: Replace all "MLB" with "Basketball", swap images, update stats/facts
  4. Map: HeroStandardApollo, SectionApollo (intro), SectionCardApollo + CardImageArticle, SectionTestimonialFalcon, SectionParallaxApollo (CTA), FooterDefault
  5. Generate pages/basketball.vue + assets/content/basketball.json

Example 2: Structural Modification

User prompt: "Use example.com as inspiration but add a video hero and remove the contact form"

Process:

  1. Capture example.com — identify all sections including the contact form
  2. Modifications: Replace standard hero with video hero, delete form section
  3. Map: HeroVideoApollo (instead of HeroStandardApollo), remove form section entirely
  4. All other sections mapped normally via rds-component-mapper
  5. Generate page files

Example 3: Complete Redesign with Same Content

User prompt: "Take our current research page and rebuild it with a modern parallax layout"

Process:

  1. Capture the research page — extract all content
  2. Modifications: Restructure as alternating content/parallax sections
  3. Map: HeroStandardApollo, then alternate SectionApollo ↔ SectionParallaxApollo
  4. Same content, completely different visual structure
  5. Generate page files with parallax-oriented layout

6. Error Handling

Error Resolution
Playwright cannot reach URL Ask user to verify URL is accessible; check for auth walls
Page requires login/auth Ask user to provide credentials or a public alternative
Reference page is a SPA with lazy loading Scroll the entire page first, wait for network idle, then snapshot
No RDS component matches a section Use SectionApollo or SectionContainerAtlas as a wrapper and compose with smaller RDS components
Content JSON structure unclear Follow the pattern from existing pages in the project; check assets/content/ for examples
Dev server not available for validation Perform code-level validation (Step 6 fallback)
Reference page has dynamic/interactive elements Translate to the closest static RDS equivalent; note limitations to user

7. Output Checklist

Before declaring the task complete, verify:

  • pages/<page-name>.vue exists and contains all sections
  • assets/content/<page-name>.json exists with all content
  • Every section uses an @rds-vue-ui/* component (no raw HTML sections)
  • No component import statements (auto-import only)
  • Content is driven by JSON, not hardcoded
  • All user-requested modifications are applied
  • <script setup> with Composition API is used
  • SCSS styling uses RDS theme variables
  • Heading hierarchy is correct (single h1, then h2s, h3s)
  • Reference screenshot and output screenshot captured (if dev server available)
  • No code was copied from the reference page source
Related skills
Installs
1
First Seen
Mar 17, 2026