Design Skills

Foundation · Design Skills

Leas Breakpoint Generator

Updated 9 June 2026

Léas Breakpoint Generator

This skill takes a Figma URL pointing to a single Léas page frame, detects which breakpoint it represents based on frame width, then duplicates it for every missing breakpoint — applying the correct frame width, Device collection appearance mode, and switching module/component variants to match the new breakpoint.

The skill never modifies source content, detaches components, or edits library files.


Breakpoint Reference

Frame NameFrame WidthAppearance ModeModule Variant
Desktop1920pxDesktopDesktop
Desktop Small1440pxDesktop SmallDesktop
Tablet768pxTabletTablet (fall back to Mobile if Tablet variant missing)
Mobile360pxMobileMobile

Key rules:

  • Desktop and Desktop Small share the same module/component variants (Desktop) — only the appearance mode differs.
  • Tablet uses the Tablet variant where it exists; fall back to Mobile variant if not.
  • The appearance mode is always set on the outermost page frame, not on individual modules.

Working File

The Léas Pages file key is: XtAs3dM0Slb79r3QyRB2bA

All breakpoint frames live on a Figma Page inside this file. Always navigate to the correct page using figma.setCurrentPageAsync() before doing any work. Use figma.root.children to list pages and match by ID extracted from the URL.

Library File Protection

Never create, modify, or delete anything inside the three Léas library files:

  • Foundations: s591K1VKecRoGrlvPNv8La
  • Components: fN89wJBxUyRq5gov4daKov
  • Modules: St7LjEebkHK6JtCEfsu4oj

Step-by-Step Workflow

Step 1 — Inspect the source frame

Use get_metadata on the node ID from the URL to read:

  • The frame's width → determines source breakpoint
  • The list of instances inside the inner Main frame — these are the modules to switch variants on

Map width → breakpoint:

1920px → Desktop
1440px → Desktop Small
768px  → Tablet
360px  → Mobile

If the width doesn't match any of these exactly, pick the nearest match and flag it to the user.

Step 2 — Confirm with the user

Before doing any Figma work, tell the user:

  • Which breakpoint you detected
  • Which breakpoints are missing and will be created

Ask: "Does this look right? Shall I proceed?"

Step 3 — Navigate to the correct page

The plugin API requires navigating to the page before finding nodes. Always do this first in every use_figma call:

// Find the page by its ID (extract from URL or scan root children)
const targetPage = figma.root.children.find(p => p.id === 'PAGE_ID_HERE');
await figma.setCurrentPageAsync(targetPage);
// Now findOne() will work correctly
const sourceFrame = figma.currentPage.findOne(n => n.id === 'NODE_ID');

Pages load lazily — a page can show children: 0 in a metadata scan but still contain nodes once navigated to.

Step 4 — Duplicate and adapt each missing breakpoint

For each missing breakpoint, run use_figma with code that:

  1. Navigates to the correct page with setCurrentPageAsync
  2. Clones the source frame with sourceFrame.clone()
  3. Renames the clone to the breakpoint name (Desktop, Desktop Small, Tablet, or Mobile)
  4. Positions it to the right of the rightmost existing frame + 100px gap
  5. Resizes the outer frame and inner Main child to the target width
  6. Sets the appearance mode using the Device collection
  7. Switches variants on all nested instances

Appearance mode — CRITICAL

The Device collection is a library collection, not local. Use getVariableCollectionById() with the full ID. Do NOT use getLocalVariableCollections() — it returns empty for library collections.

const DEVICE_COLLECTION_ID = 'VariableCollectionId:1f86617ff9c6bd5b63fc7f311069c3fdd3c21bd4/9947:304';
const deviceCollection = figma.variables.getVariableCollectionById(DEVICE_COLLECTION_ID);

// Known stable mode IDs (confirmed from live file):
// Desktop       → '7985:0'
// Desktop Small → '9837:0'
// Tablet        → '7985:2'
// Mobile        → '7985:3'

if (deviceCollection) {
  const mode = deviceCollection.modes.find(m => m.name === targetAppearanceName);
  if (mode) {
    clonedFrame.setExplicitVariableModeForCollection(deviceCollection, mode.modeId);
  }
}

Variant switching — Device is king

Device is the authoritative property. Some modules have additional variant properties that only apply to certain breakpoints (e.g. Position=Left/Right on Desktop Promo Spotlight, which doesn't exist on Mobile). Always set Device in isolation — never in a combined setProperties call with other properties — to avoid Figma throwing on property combinations that don't exist in the target variant set.

function switchVariants(node, targetVariant, results) {
  if (node.type === 'INSTANCE') {
    const props = node.componentProperties;
    if (props) {
      const devicePropKey = Object.keys(props).find(k => k.startsWith('Device'));
      if (devicePropKey) {

        // Resolve the correct Device value for this node name
        let deviceValue = targetVariant;

        // Special case: Breadcrumbs only accepts 'Desktop', 'Mobile Expanded', 'Mobile Short'
        if (node.name === 'Breadcrumbs') {
          deviceValue =
            targetVariant === 'Desktop' ? 'Desktop' :
            targetVariant === 'Tablet'  ? 'Mobile Expanded' :
                                          'Mobile Short';
        }

        // Special case: Download Card - [SLOT ONLY] uses 'Desktop+Tablet' on Tablet
        if (node.name === 'Download Card - [SLOT ONLY]') {
          deviceValue = targetVariant === 'Tablet' ? 'Desktop+Tablet' : targetVariant;
        }

        // Special case: Two CTAs - [SLOT ONLY] uses 'Desktop' on Tablet
        if (node.name === 'Two CTAs - [SLOT ONLY]') {
          deviceValue = targetVariant === 'Tablet' ? 'Desktop' : targetVariant;
        }

        // Special case: Promo Spotlight has a 'Media Position' property (Left/Right)
        // that only applies to Desktop. On Tablet and Mobile, content stacks and the
        // property becomes irrelevant — whatever value Figma assigns after the Device
        // switch is fine. Never attempt to preserve or set Media Position on non-Desktop
        // breakpoints, as doing so may conflict with the target variant set.
        // (No code change needed here — the Device-only set below already handles this.
        //  This comment is a guard: do NOT add Media Position to any setProperties call
        //  for Promo Spotlight when targetVariant is Tablet or Mobile.)

        // Always set Device alone — never batch with other properties.
        // Other variant properties (e.g. Position, Style) may not exist on the
        // target breakpoint's variant set and would cause setProperties to throw.
        try {
          node.setProperties({ [devicePropKey]: deviceValue });
        } catch (e) {
          // Tablet fallback: if no Tablet variant exists, use Mobile
          if (targetVariant === 'Tablet' && deviceValue === 'Tablet') {
            try {
              node.setProperties({ [devicePropKey]: 'Mobile' });
              results.tabletFallbacks.push(node.name);
            } catch (e2) {
              results.variantFailures.push({ name: node.name, reason: String(e2) });
            }
          } else {
            results.variantFailures.push({ name: node.name, reason: String(e) });
          }
        }
      }
    }
  }
  if ('children' in node) {
    for (const child of node.children) switchVariants(child, targetVariant, results);
  }
}

Resize pattern — width and height

Resize width first, then after all variant switches are complete, compute the true height by summing the children of Main. Do not hard-code or carry over the source height — modules are taller or shorter at different breakpoints.

// Step 1 — resize width
clonedFrame.resize(targetWidth, clonedFrame.height);
const mainChild = clonedFrame.children.find(c => c.name === 'Main');
if (mainChild) mainChild.resize(targetWidth, mainChild.height);

// ... run switchVariants() and setExplicitVariableModeForCollection() here ...

// Step 2 — recompute height after all changes have been applied
// Wait one microtask tick so Figma can propagate auto-layout changes
await new Promise(r => setTimeout(r, 0));

if (mainChild && mainChild.children.length > 0) {
  // Sum the heights of all visible direct children of Main
  let totalHeight = 0;
  for (const child of mainChild.children) {
    if (child.visible !== false) {
      totalHeight = Math.max(totalHeight, child.y + child.height);
    }
  }
  if (totalHeight > 0) {
    mainChild.resize(targetWidth, totalHeight);
    clonedFrame.resize(targetWidth, totalHeight);
  }
} else {
  // No Main wrapper — use the frame's own children
  let totalHeight = 0;
  for (const child of clonedFrame.children) {
    if (child.visible !== false) {
      totalHeight = Math.max(totalHeight, child.y + child.height);
    }
  }
  if (totalHeight > 0) clonedFrame.resize(targetWidth, totalHeight);
}

If Main uses Figma auto-layout (hugging), its height will already be correct after the variant switch — the resize above will simply match what Figma computed. Either way the outer frame is always brought into sync.

Step 5 — Naming

Name each new frame simply after its breakpoint: Desktop, Desktop Small, Tablet, Mobile. Do not rename the source frame.

Step 6 — Post-build summary

Report:

  • Breakpoints created, with node IDs
  • Modules where Tablet variant was missing and fell back to Mobile
  • Any variant switches that failed outright (module name + reason)

Breakpoint-specific variant mappings (confirmed from live file)

ComponentDesktopDesktop SmallTabletMobile
NavbarDesktopDesktopTabletMobile
BreadcrumbsDesktopDesktopMobile ExpandedMobile Short
Download Card - [SLOT ONLY]DesktopDesktopDesktop+TabletMobile
Two CTAs - [SLOT ONLY]DesktopDesktopDesktopMobile
Promo SpotlightDesktop + Media Position (Left/Right)Desktop + Media PositionTablet or fallback Mobileignore Media PositionMobileignore Media Position
Most modulesDesktopDesktopTablet or fallback MobileMobile

Edge Cases

Source is already one of the target breakpoints — skip it, create only the others.

Breakpoint already exists on the page — scan page.children for frames matching the target width or name, and skip. Do not overwrite.

Tablet variant missing — use Mobile variant and flag in the summary.

Module has no Device property — leave it as-is; the appearance mode handles layout via tokens. Note it in the summary.

Promo Spotlight Media Position on Tablet/MobileMedia Position (Left/Right) is a Desktop-only concern. When generating Tablet or Mobile frames, only set the Device property on Promo Spotlight instances. Do not attempt to read, preserve, or set Media Position — it does not exist on the Tablet/Mobile variant set and Figma will assign a valid default automatically.

Main inner wrapper absent — iterate clonedFrame.children directly.


What This Skill Does NOT Do

  • Does not edit any text content
  • Does not detach any components from the library
  • Does not modify the source frame
  • Does not create new components or styles
  • Does not touch the three Léas library files