<?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: Eyal Ellenbogen</title>
    <description>The latest articles on DEV Community by Eyal Ellenbogen (@eyal_ellenbogen).</description>
    <link>https://dev.to/eyal_ellenbogen</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%2F4151005%2Fb5020c11-aac8-4ff3-9407-1510b88fd6ce.jpg</url>
      <title>DEV Community: Eyal Ellenbogen</title>
      <link>https://dev.to/eyal_ellenbogen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eyal_ellenbogen"/>
    <language>en</language>
    <item>
      <title>Living the design-to-code dream</title>
      <dc:creator>Eyal Ellenbogen</dc:creator>
      <pubDate>Thu, 29 Oct 2026 02:33:36 +0000</pubDate>
      <link>https://dev.to/eyal_ellenbogen/living-the-design-to-code-dream-1ehj</link>
      <guid>https://dev.to/eyal_ellenbogen/living-the-design-to-code-dream-1ehj</guid>
      <description>&lt;p&gt;This flow should sound familiar to any frontend developer: a designer makes a change in Figma, and now we need to propagate it to our code. By nature, that process involves an entire handoff from UX to engineering. As a company matures, it quickly realizes this flow will not scale. When those changes are not aligned in the code right away, we get drift. The UX team ends up sketching UI with updated assets while production screens still show up with old colors, spacing, and typography.&lt;/p&gt;

&lt;p&gt;Scaling this process means automating it, and today's design tools do not make that easy out of the box. Off-the-shelf integrations make assumptions about repository structure, token formats, and release workflows that rarely match an existing organizational stack. Most teams end up building a custom bridge of their own.&lt;/p&gt;

&lt;p&gt;This note walks through one approach that puts the ideas from &lt;a href="https://ellenblogen.com/handbook/design-tools-tokens-and-implementation" rel="noopener noreferrer"&gt;design tools, tokens, and implementation&lt;/a&gt; into practice. The goal is to satisfy both sides of the handoff: designers stay focused on design without having to learn code, version control, or release mechanics, while engineers still get a reviewable diff, an approval gate, and a versioned package. We will be focusing on tokens here, though the same pattern applies to icons.&lt;/p&gt;

&lt;h2&gt;
  
  
  The shape of the bridge
&lt;/h2&gt;

&lt;p&gt;There's more than one way to build this bridge. The source of truth for design tokens can sit either in Figma or in Git. With Git as the source, tokens are authored in the repository and Figma consumes them, just like our codebase does. That keeps the repository authoritative, but designers end up editing tokens somewhere other than the canvas. Our example goes the other way and makes Figma the source of truth, because it is friendlier to designers, who keep working in the tool they already know.&lt;/p&gt;

&lt;p&gt;With Figma in the driver's seat, the pipeline splits into two halves: a Figma plugin that turns canvas edits into a pull request, and a CI workflow that turns the merged pull request into a versioned package. The repository tracks only a single raw JSON snapshot of the tokens, while all code artifacts are generated on release.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Designer:&lt;/strong&gt; Figma plugin → &lt;strong&gt;Review:&lt;/strong&gt; Pull request → &lt;strong&gt;Automation:&lt;/strong&gt; CI workflow → &lt;strong&gt;Release:&lt;/strong&gt; Versioned package&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The designer publishes from Figma, engineers approve the PR, and the pipeline generates code and releases a version.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Inside the plugin
&lt;/h2&gt;

&lt;p&gt;Our workflow starts when a designer has changes they want to publish. Opening our custom-built Figma plugin shows them their pending changes alongside a simple screen to publish their work.&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%2Fnkigqly53jaxbzonhd98.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%2Fnkigqly53jaxbzonhd98.png" alt="Token Publisher plugin, Changes tab: six pending changes in the Semantic collection, each showing the old and new value." width="800" height="1204"&gt;&lt;/a&gt;&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%2Fgi51gf06yxla2z8oi9zd.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%2Fgi51gf06yxla2z8oi9zd.png" alt="Token Publisher plugin, Publish tab: six changes since the last release, a message that the release adds new tokens and nothing breaks, an optional note field, and a Publish button." width="800" height="1204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Changes" lists what differs from the last release. "Publish" says what kind of release this is and takes an optional note for engineers.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Behind the scenes, the plugin compares the current Figma variables with the token file on &lt;code&gt;main&lt;/code&gt;. It does more than list what differs. It tells the designer, in plain language, what kind of release this is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Updated existing values&lt;/strong&gt; (&lt;code&gt;patch&lt;/code&gt;): colors, sizes, or other values changed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Added new tokens&lt;/strong&gt; (&lt;code&gt;minor&lt;/code&gt;): new tokens that didn't exist before.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Removed or renamed tokens&lt;/strong&gt; (&lt;code&gt;major&lt;/code&gt;): tokens were deleted or their names changed, which breaks any app that uses them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The designer adds a note for engineers and presses "Publish". The plugin then commits the snapshot to a branch and opens a pull request, using the note as its description. After publishing, the designer sees where the request stands.&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%2F68qy88b3pb2epjzcl4kr.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%2F68qy88b3pb2epjzcl4kr.png" alt="Token Publisher plugin, Publish tab with a removed token: a breaking change message explains that apps using the token will need to switch to another one." width="800" height="1204"&gt;&lt;/a&gt;&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%2Fp124511or759y0svjntl.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%2Fp124511or759y0svjntl.png" alt="Token Publisher plugin confirmation: Sent for review, with three steps: sent from Figma, engineering review, and release." width="800" height="1204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A removed token is called out as a breaking change before anything is sent. After publishing, the designer sees what happens next.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling incremental changes
&lt;/h2&gt;

&lt;p&gt;Figma holds a single live state, so two designers never conflict inside it. Git is where conflicts appear, because every publish is a snapshot of that state taken at a different moment, and a newer snapshot already contains everything an older one did.&lt;/p&gt;

&lt;p&gt;So the plugin never opens a second pull request. Each publish either opens one or, if one is already open, updates it with the latest snapshot. Two designers publishing on the same afternoon end up in the same pull request, and its diff always compares &lt;code&gt;main&lt;/code&gt; with the current state of Figma.&lt;/p&gt;

&lt;h2&gt;
  
  
  Versioning our package
&lt;/h2&gt;

&lt;p&gt;After a merge, the pipeline compares the token file with the copy at the latest git tag and derives the &lt;code&gt;major&lt;/code&gt;, &lt;code&gt;minor&lt;/code&gt;, or &lt;code&gt;patch&lt;/code&gt; bump from those same rules. When a release mixes them, the highest one wins. It then reads the latest tag, applies the bump, publishes the package, and pushes the next tag.&lt;/p&gt;

&lt;p&gt;Because those rules follow the token names applications depend on, a drastic color change is still a &lt;code&gt;patch&lt;/code&gt;. How much a change matters visually belongs in the designer's note and in review, while the version number reflects the contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's in the box?
&lt;/h2&gt;

&lt;p&gt;From the single JSON snapshot, the pipeline generates everything applications need, in the formats each implementation prefers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SCSS variables&lt;/strong&gt; for stylesheets that rely on compile-time values.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript constants&lt;/strong&gt; for code that needs tokens in JavaScript, exposed in whichever shape suits the consumer.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pipeline generates CSS custom properties as well, though the compiled options are the better choice. With them, a removed or renamed token breaks the build of any application still using it, which is exactly what a &lt;code&gt;major&lt;/code&gt; bump promises. A CSS custom property that no longer exists fails silently at runtime, so the handshake between design and code only sticks when the compiler is in on it. Custom properties still earn their place for runtime theming, such as switching between light and dark modes without recompiling.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dream come true
&lt;/h2&gt;

&lt;p&gt;With that, we have ourselves a fully automated workflow, taking a change on the canvas all the way to a versioned package. Ours is just one approach among many, of course. The real takeaway is that automating the handoff is key, and doing it well means separating the designer experience from the developer experience. Once we build the bridge that ties them together, the drift between canvas and production disappears.&lt;/p&gt;

</description>
      <category>designsystems</category>
      <category>figma</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>UI Architecture That AI Coding Agents Can Actually Use</title>
      <dc:creator>Eyal Ellenbogen</dc:creator>
      <pubDate>Wed, 30 Sep 2026 03:10:37 +0000</pubDate>
      <link>https://dev.to/eyal_ellenbogen/ui-architecture-that-ai-coding-agents-can-actually-use-m84</link>
      <guid>https://dev.to/eyal_ellenbogen/ui-architecture-that-ai-coding-agents-can-actually-use-m84</guid>
      <description>&lt;p&gt;When we ask an AI agent to "add a confirmation modal before deleting a user," we expect a focused pull request. What we usually get is an archaeological expedition.&lt;/p&gt;

&lt;p&gt;Without clear module boundaries, the agent's first job is excavation: deciphering undocumented state, tracing network calls across files, and guessing where UI decisions belong. It imports a global store here, tweaks a shared utility there, and produces a sprawling diff that touches unrelated files.&lt;/p&gt;

&lt;p&gt;The problem isn't the model's reasoning. It's that the codebase gives it infinite room to wander.&lt;/p&gt;

&lt;h2&gt;
  
  
  A bounded perimeter
&lt;/h2&gt;

&lt;p&gt;An agent needs to know where its task begins and, crucially, where it stops. In a tangled codebase, a simple visual adjustment can cascade into root layouts, authentication guards, and global routers.&lt;/p&gt;

&lt;p&gt;Bounded feature packages provide a tight operational perimeter. Because the feature lives in its own package with a deliberate public API, the agent's context stays focused on the slice of code that matters. Modularity helps human code reviewers—and keeps an automated tool confined to the task at hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Explicit contracts over inferred intent
&lt;/h2&gt;

&lt;p&gt;Without interfaces, agents are forced to infer product rules from implementation details. If a screen calls an HTTP client directly, the agent has to reverse-engineer server payloads and guess whether a data transformation is a business rule or a temporary workaround.&lt;/p&gt;

&lt;p&gt;Behind a port, the contract is explicit. The agent inspects view models and UI commands defined in the feature's &lt;a href="https://ellenblogen.com/handbook/the-parts-of-a-feature" rel="noopener noreferrer"&gt;API contract&lt;/a&gt;. It can wire up a modal, handle validation states, and report user intent without touching transport logic or risking regressions in other parts of the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verifiable sandboxes
&lt;/h2&gt;

&lt;p&gt;An agent needs fast, observable evidence that it implemented the requested behavior correctly. If verifying a change requires a live backend, a populated staging database, and an authenticated VPN session, the agent is flying blind.&lt;/p&gt;

&lt;p&gt;The feature's &lt;a href="https://ellenblogen.com/handbook/testing-a-feature-without-the-host" rel="noopener noreferrer"&gt;demo harness&lt;/a&gt; gives the agent a deterministic sandbox. Because the view runs against mock fixtures through its port, an agent can bring up loading, empty, error, and success states. It can run interaction checks, inspect the resulting DOM, and verify the change before opening a pull request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compiler constraints beat system prompts
&lt;/h2&gt;

&lt;p&gt;Attempting to guardrail an agent with natural language prompts is brittle. Rules documented in prompt files can degrade across conversations, get misinterpreted, or be bypassed under pressure.&lt;/p&gt;

&lt;p&gt;Mechanical boundaries don't negotiate. When package graphs, type contracts, and lint rules enforce the boundaries, violations fail the check instead of relying on an agent to remember every instruction.&lt;/p&gt;

&lt;h2&gt;
  
  
  The architectural payoff
&lt;/h2&gt;

&lt;p&gt;Frontend architecture has never been about aesthetic perfection or abstraction for its own sake.&lt;/p&gt;

&lt;p&gt;Every boundary—from separating appearance from behavior to defining ports and isolating packages—serves sustained delivery speed.&lt;/p&gt;

&lt;p&gt;The architecture that protects human engineers from cognitive overload and cascading regressions also gives agents a useful scope and a way to verify their work. When our boundaries are real, both can move faster without expanding the risk of each change.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article is an excerpt from chapter 22 of my &lt;a href="https://ellenblogen.com/handbook" rel="noopener noreferrer"&gt;UI Architecture Handbook&lt;/a&gt;—a guide to frontend boundaries, design systems, and delivery velocity.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>ui</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
