<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Piotr Godycki</title>
    <description>The latest articles on DEV Community by Piotr Godycki (@piotrgodycki).</description>
    <link>https://dev.to/piotrgodycki</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F536647%2F7012c19a-dd89-41ef-b5f3-6d701f21b7c2.jpeg</url>
      <title>DEV Community: Piotr Godycki</title>
      <link>https://dev.to/piotrgodycki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/piotrgodycki"/>
    <language>en</language>
    <item>
      <title>From a Figma frame to an AEM EDS block in one command</title>
      <dc:creator>Piotr Godycki</dc:creator>
      <pubDate>Tue, 03 Nov 2026 22:30:01 +0000</pubDate>
      <link>https://dev.to/piotrgodycki/from-a-figma-frame-to-an-aem-eds-block-in-one-command-2m6</link>
      <guid>https://dev.to/piotrgodycki/from-a-figma-frame-to-an-aem-eds-block-in-one-command-2m6</guid>
      <description>&lt;p&gt;If you build sites on &lt;strong&gt;AEM Edge Delivery Services (EDS)&lt;/strong&gt;, you know the loop: a designer sends a Figma link, and you rebuild the frame by hand as a block: &lt;code&gt;decorate()&lt;/code&gt; JS, scoped CSS and a Universal Editor model. Then the next frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.npmjs.com/package/aem-eds-kit" rel="noopener noreferrer"&gt;aem-eds-kit&lt;/a&gt;&lt;/strong&gt; turns that into one command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds block from-design &lt;span class="s2"&gt;"&amp;lt;Figma frame link&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; hero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This post walks through it step by step: setting up Figma access (REST or MCP), preparing the file, generating the block, and staying inside Figma's rate limits. At the end there's a reference of every option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fva5b9qr7upyuasni38gv.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fva5b9qr7upyuasni38gv.webp" alt="A design next to the EDS block eds generated from it" width="800" height="236"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Figma frame
    │  read once (REST or MCP), cached
    ▼
design spec  ──►  prompt: EDS rules + your project's design tokens
                              │
                              ▼
          your AI agent (Claude Code, Cursor or Codex)
                              │
                              ▼
 blocks/hero/  hero.js · hero.css · _hero.json (UE model) · _hero.preview.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;eds&lt;/code&gt; reads the frame&lt;/strong&gt;: layout, Auto Layout, text styles, Variables, variants and frame widths.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It builds a prompt&lt;/strong&gt;: how EDS markup looks, how to write &lt;code&gt;decorate()&lt;/code&gt;, which of the 17 Universal Editor field types fits each layer, and your project's design tokens from &lt;code&gt;styles/styles.css&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AI coding agent you already use writes the block&lt;/strong&gt;: &lt;code&gt;eds&lt;/code&gt; doesn't ship a model of its own.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1: Install
&lt;/h2&gt;

&lt;p&gt;You need &lt;strong&gt;Node.js 20+&lt;/strong&gt; and &lt;strong&gt;Claude Code, Cursor or Codex&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; aem-eds-kit@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You also need an EDS project. If you don't have one, clone Adobe's latest boilerplate (no GitHub login needed):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds new my-site       &lt;span class="c"&gt;# pick: Document Authoring / DA, Universal Editor, or Commerce&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;my-site
eds init              &lt;span class="c"&gt;# set it up for your authoring model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 2: Connect to Figma (REST or MCP)
&lt;/h2&gt;

&lt;p&gt;Figma draws designs on a canvas, not in HTML, so the frame has to come from Figma itself. There are two ways in. &lt;strong&gt;You only need one.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;
&lt;strong&gt;REST&lt;/strong&gt; (recommended)&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;MCP&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Who reads the design&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;eds&lt;/code&gt; itself, over Figma's REST API&lt;/td&gt;
&lt;td&gt;Your AI agent, through its Figma MCP server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;You need&lt;/td&gt;
&lt;td&gt;A Figma personal access token&lt;/td&gt;
&lt;td&gt;Your agent connected to Figma's MCP server&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with a local model (Ollama, oMLX)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost per block&lt;/td&gt;
&lt;td&gt;1 REST call, then cached&lt;/td&gt;
&lt;td&gt;1 MCP call, then cached&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Option A: REST (a token)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Figma, open &lt;strong&gt;Settings → Security → Personal access tokens&lt;/strong&gt; and generate a token with &lt;strong&gt;File content: read&lt;/strong&gt; (&lt;code&gt;file_content:read&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Give it to &lt;code&gt;eds&lt;/code&gt;, either as an environment variable:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FIGMA_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;figd_your_token
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or once in &lt;code&gt;~/.eds/config.json&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"figma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"figd_your_token"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. With a token set, &lt;code&gt;eds&lt;/code&gt; fetches the frame itself and embeds a compact spec in the prompt. Treat the token like a password and keep it out of your repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option B: MCP (no token)
&lt;/h3&gt;

&lt;p&gt;Connect your agent to Figma's MCP server: Figma's remote server, or the local one built into the Figma desktop app (turn it on in Dev Mode; it runs at &lt;code&gt;http://127.0.0.1:3845/mcp&lt;/code&gt;). Not sure what your agent needs? Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds figma setup
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It detects your agent (Claude Code, Cursor or Codex), checks whether Figma MCP is connected, prints the exact command or config to add it if not, and saves your choice.&lt;/p&gt;

&lt;p&gt;With MCP, the agent makes &lt;strong&gt;one&lt;/strong&gt; &lt;code&gt;get_design_context&lt;/code&gt; call per block, and &lt;code&gt;eds&lt;/code&gt; caches the result. If you have a token but want MCP for a run, add &lt;code&gt;--mcp&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Prepare the frame
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;eds&lt;/code&gt; reads what's in the file, so a tidy frame gives a better block:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One top-level frame per block&lt;/strong&gt;, named after the block in kebab-case: &lt;code&gt;hero&lt;/code&gt;, &lt;code&gt;cards&lt;/code&gt;, &lt;code&gt;cta-banner&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto Layout everywhere.&lt;/strong&gt; It becomes flex / grid with the right gaps and padding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layers named by role&lt;/strong&gt;, not looks: &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;description&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, &lt;code&gt;cta&lt;/code&gt;. These become the Universal Editor fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Colours, spacing, radii and font sizes bound to Variables&lt;/strong&gt; (&lt;code&gt;color/brand&lt;/code&gt;, &lt;code&gt;spacing/m&lt;/code&gt;). They map to CSS custom properties.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Variants for block variations&lt;/strong&gt; (&lt;code&gt;Theme=dark&lt;/code&gt;, &lt;code&gt;Layout=image-left&lt;/code&gt;) and boolean properties for optional parts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The same block at 2–3 widths&lt;/strong&gt; (e.g. 390 / 768 / 1440). &lt;code&gt;eds&lt;/code&gt; records the frame widths and uses them as the preview breakpoints.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 4: Generate the block
&lt;/h2&gt;

&lt;p&gt;In Figma, right-click the frame → &lt;strong&gt;Copy link to selection&lt;/strong&gt;. Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds block from-design &lt;span class="s2"&gt;"https://www.figma.com/design/&amp;lt;file&amp;gt;/&amp;lt;name&amp;gt;?node-id=12-345"&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; hero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What happens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;eds&lt;/code&gt; reads the frame (REST or MCP) and caches it.&lt;/li&gt;
&lt;li&gt;It builds the prompt and hands it to your agent. You see a live log.&lt;/li&gt;
&lt;li&gt;It checks the result: the files exist, &lt;code&gt;decorate()&lt;/code&gt; is exported, the CSS is scoped to the block, and the Universal Editor model is valid.&lt;/li&gt;
&lt;li&gt;You get a menu: &lt;strong&gt;Refine&lt;/strong&gt; (describe a change for another pass), &lt;strong&gt;Open live preview&lt;/strong&gt;, or &lt;strong&gt;Finish&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;blocks/hero/
├── hero.js              # decorate(block)
├── hero.css             # styles, scoped to .hero
├── _hero.json           # Universal Editor model: one field per layer
├── _hero.preview.html   # sample content in real EDS markup
└── .eds-meta.json       # the Figma source and the frame widths
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The block ships with &lt;strong&gt;placeholder copy and image slots&lt;/strong&gt; until authors fill them in. The layout, spacing, type, colours and backgrounds come from the frame.&lt;/p&gt;

&lt;p&gt;Want to see what would be sent first? &lt;code&gt;--dry-run&lt;/code&gt; builds the prompt without running the agent.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Preview and check
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds block preview hero     &lt;span class="c"&gt;# the block at the frame widths, live reload&lt;/span&gt;
eds block check hero       &lt;span class="c"&gt;# accessibility: alt text, image sizes, link names…&lt;/span&gt;
eds block &lt;span class="nb"&gt;test &lt;/span&gt;hero        &lt;span class="c"&gt;# visual regression against a saved baseline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo89tdtb6qtumipranubs.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo89tdtb6qtumipranubs.webp" alt="The block preview in the browser" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With a REST token, &lt;code&gt;eds block test hero --design&lt;/code&gt; also compares the rendered block against the frame's image from Figma.&lt;/p&gt;

&lt;p&gt;The block is just files in &lt;code&gt;blocks/&lt;/code&gt;, so &lt;code&gt;aem up&lt;/code&gt; shows it in a real page.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Mind Figma's limits
&lt;/h2&gt;

&lt;p&gt;Figma counts both REST and MCP calls, and the limit depends on &lt;strong&gt;the plan that owns the file&lt;/strong&gt;, not on your seat in some other team:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Starter&lt;/th&gt;
&lt;th&gt;Professional&lt;/th&gt;
&lt;th&gt;Organization&lt;/th&gt;
&lt;th&gt;Enterprise&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;REST, Dev / Full seat&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;td&gt;10 / min&lt;/td&gt;
&lt;td&gt;15 / min&lt;/td&gt;
&lt;td&gt;20 / min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MCP, Dev / Full seat&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;td&gt;200 / day&lt;/td&gt;
&lt;td&gt;200 / day&lt;/td&gt;
&lt;td&gt;600 / day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;View / Collab seat (both)&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;td&gt;20 / month&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;eds&lt;/code&gt; keeps you inside them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One call per block&lt;/strong&gt;, then a cache, so refine passes and retries are free. &lt;code&gt;--refresh&lt;/code&gt; reads the frame again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;REST calls are paced per minute&lt;/strong&gt;, even when you generate several blocks in parallel (&lt;code&gt;figma.restPerMinute&lt;/code&gt;, default 10; use 15 on Organization, 20 on Enterprise).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A short &lt;code&gt;429&lt;/code&gt; is waited out.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A plan cap stops the run&lt;/strong&gt; and tells you when the limit resets. &lt;code&gt;eds&lt;/code&gt; never silently falls back to spending your MCP budget.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On a Starter plan&lt;/strong&gt;, the cheapest route is to export the frame (right-click → &lt;strong&gt;Export&lt;/strong&gt; → PNG or SVG) and pass the file. That uses no Figma calls at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds block from-design ./hero.svg &lt;span class="nt"&gt;--name&lt;/span&gt; hero
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An SVG keeps the text and shapes readable; a PNG works too.&lt;/p&gt;




&lt;h2&gt;
  
  
  Going further with the block
&lt;/h2&gt;

&lt;p&gt;Once the block is generated, a few commands build on it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds model add hero teaser              &lt;span class="c"&gt;# add reusable field groups to the UE model (image, cta, teaser…)&lt;/span&gt;
eds track block hero                   &lt;span class="c"&gt;# dataLayer tracking: clicks and form submits&lt;/span&gt;
eds schema block hero &lt;span class="nt"&gt;--type&lt;/span&gt; Article   &lt;span class="c"&gt;# JSON-LD structured data for SEO&lt;/span&gt;
eds ue check                           &lt;span class="c"&gt;# which blocks are editable in the Universal Editor&lt;/span&gt;
eds ue open /                          &lt;span class="c"&gt;# open a page in the Universal Editor&lt;/span&gt;
eds template new home &lt;span class="nt"&gt;--blocks&lt;/span&gt; header,hero,footer   &lt;span class="c"&gt;# a page made of your blocks&lt;/span&gt;
eds preview /home &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; eds publish /home              &lt;span class="c"&gt;# to *.aem.page, then *.aem.live&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Free: no agent, no MCP, no Figma calls
&lt;/h2&gt;

&lt;p&gt;Generating from a design needs an AI agent. Everything else in &lt;code&gt;eds&lt;/code&gt; is deterministic: plain code generation that runs offline and costs nothing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;eds new my-site                      &lt;span class="c"&gt;# clone the latest EDS boilerplate&lt;/span&gt;
eds init                             &lt;span class="c"&gt;# set it up for your authoring model&lt;/span&gt;
eds block create hero                &lt;span class="c"&gt;# an empty block: hero.js, hero.css and a UE model&lt;/span&gt;
eds scaffold ue                      &lt;span class="c"&gt;# Universal Editor config (component definitions, models, filters)&lt;/span&gt;
eds scaffold blocks                  &lt;span class="c"&gt;# the standard EDS blocks, ready for UE&lt;/span&gt;
eds scaffold helpers                 &lt;span class="c"&gt;# shared helper functions&lt;/span&gt;
eds model add hero teaser            &lt;span class="c"&gt;# add ready-made field groups to a block's UE model&lt;/span&gt;
eds schema block hero &lt;span class="nt"&gt;--type&lt;/span&gt; Article &lt;span class="c"&gt;# JSON-LD structured data&lt;/span&gt;
eds track block hero                 &lt;span class="c"&gt;# dataLayer click and form tracking&lt;/span&gt;
eds migrate component &amp;lt;&lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;          &lt;span class="c"&gt;# a classic AEM component → block + UE model&lt;/span&gt;
eds template new home &lt;span class="nt"&gt;--blocks&lt;/span&gt; hero  &lt;span class="c"&gt;# a page made of your blocks&lt;/span&gt;
eds block check                      &lt;span class="c"&gt;# accessibility and content checks&lt;/span&gt;
eds block &lt;span class="nb"&gt;test&lt;/span&gt;                       &lt;span class="c"&gt;# visual regression&lt;/span&gt;
eds doctor                           &lt;span class="c"&gt;# project health; also eds audit loading / security&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for designs, two ways to spend nothing on Figma or a cloud model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;eds block from-design "&amp;lt;frame link&amp;gt;" --dry-run&lt;/code&gt; (or &lt;code&gt;--agent none&lt;/code&gt;) saves the full prompt to a file without calling any agent. Paste it into any AI chat you like.&lt;/li&gt;
&lt;li&gt;Export the frame as PNG or SVG (no Figma calls), then generate with a local model: &lt;code&gt;--agent ollama&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  All the options
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;eds block from-design&lt;/code&gt;
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--name &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Block name (otherwise taken from the frame)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--mcp&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use Figma MCP even when a REST token is set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--refresh&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read the frame again instead of using the cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--screenshot&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Add one MCP screenshot call for a pixel check (costs a call)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--source &amp;lt;type&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Where content comes from: &lt;code&gt;document&lt;/code&gt; (default), &lt;code&gt;ue&lt;/code&gt;, &lt;code&gt;cf&lt;/code&gt; (Content Fragment) or &lt;code&gt;mixed&lt;/code&gt;; &lt;code&gt;cf&lt;/code&gt; / &lt;code&gt;mixed&lt;/code&gt; default to the &lt;code&gt;sonnet&lt;/code&gt; model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--no-ue-model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Skip the Universal Editor model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--widths &amp;lt;list&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview breakpoints, e.g. &lt;code&gt;390,768,1440&lt;/code&gt;, if the file has only one frame width&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--agent &amp;lt;type&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;claude&lt;/code&gt;, &lt;code&gt;cursor&lt;/code&gt;, &lt;code&gt;codex&lt;/code&gt;, &lt;code&gt;ollama&lt;/code&gt;, &lt;code&gt;omlx&lt;/code&gt;, &lt;code&gt;local&lt;/code&gt;, or &lt;code&gt;none&lt;/code&gt; (just save the prompt)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--model &amp;lt;name&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;The model to use, e.g. &lt;code&gt;sonnet&lt;/code&gt;, or a local one like &lt;code&gt;qwen2.5-coder:14b&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--dry-run&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Only build and show the prompt, don't run the agent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--serve&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start the live preview right after generating (non-interactive runs)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--yes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No questions, use defaults&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With no arguments, &lt;code&gt;eds block from-design&lt;/code&gt; runs a step-by-step wizard.&lt;/p&gt;

&lt;h3&gt;
  
  
  Preview and checks
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Command&lt;/th&gt;
&lt;th&gt;Options&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eds block preview [name]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--widths &amp;lt;list&amp;gt;&lt;/code&gt; breakpoints · &lt;code&gt;--port &amp;lt;port&amp;gt;&lt;/code&gt; · &lt;code&gt;--no-open&lt;/code&gt; don't open the browser. No name: a gallery of all blocks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eds block test [name]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--update&lt;/code&gt; save new baselines · &lt;code&gt;--threshold &amp;lt;ratio&amp;gt;&lt;/code&gt; allowed change (default &lt;code&gt;0.01&lt;/code&gt; = 1%) · &lt;code&gt;--design&lt;/code&gt; compare against the Figma frame image (needs a token) · &lt;code&gt;--widths&lt;/code&gt; · &lt;code&gt;--port&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;eds block check [name]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;--strict&lt;/code&gt; fail on warnings too · &lt;code&gt;--widths&lt;/code&gt; · &lt;code&gt;--port&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;No name in &lt;code&gt;test&lt;/code&gt; / &lt;code&gt;check&lt;/code&gt; means all blocks. Both exit non-zero on failure, so they fit in CI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration (&lt;code&gt;~/.eds/config.json&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"agent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"claude"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sonnet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"figma"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"figd_…"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"restPerMinute"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Key&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;agent&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default agent, so you can drop &lt;code&gt;--agent&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Default model (the built-in default is the fastest, Haiku; &lt;code&gt;sonnet&lt;/code&gt; is more faithful)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;figma.token&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;REST token; the &lt;code&gt;FIGMA_TOKEN&lt;/code&gt; env variable works too&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;figma.restPerMinute&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;REST calls per minute across parallel runs: 10 (Professional), 15 (Organization), 20 (Enterprise)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Priority: command-line flags → env variables → &lt;code&gt;.edsrc.json&lt;/code&gt; in the project → &lt;code&gt;~/.eds/config.json&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Global flags (any command)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--verbose&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Debug output&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--quiet&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Errors only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;JSON output (&lt;code&gt;doctor&lt;/code&gt;, &lt;code&gt;audit loading&lt;/code&gt;, &lt;code&gt;audit security&lt;/code&gt;, &lt;code&gt;block list&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--no-color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;No colours (also respects &lt;code&gt;NO_COLOR&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Or skip the flags entirely: type &lt;code&gt;eds&lt;/code&gt; and pick from the menu (arrows, Enter, Esc to go back).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fry4nmgj6u4kp4cebrqan.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fry4nmgj6u4kp4cebrqan.png" alt="The eds interactive menu" width="799" height="421"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The same CLI also takes Framer and Google Stitch pages, migrates classic AEM components into EDS blocks, and runs on a local model (Ollama, oMLX). All of that is in the &lt;strong&gt;&lt;a href="https://piotrgodycki.github.io/aem-eds-kit/docs.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;&lt;/strong&gt;. Code: &lt;strong&gt;&lt;a href="https://github.com/piotrgodycki/aem-eds-kit" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/strong&gt; (MIT).&lt;/p&gt;

&lt;p&gt;Questions or ideas? Tell me in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;aem-eds-kit is an independent open-source project, not affiliated with Adobe or Figma.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aem</category>
      <category>figma</category>
      <category>webdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
