Builder · Figma plugin · Birdeye

Real-time UX writing
validation, inside Figma

A Figma plugin that reviews UI copy against an internal style guide the moment a designer selects a text layer. No Slack ping. No async review. No back-and-forth.

Solo builder · content designer
Figma API · Deno · OpenAI
VS Code · Cursor · TypeScript
Employee of the Month

Why it mattered

Zero wait time Designers get copy feedback without leaving Figma or pinging the content team.
16 component types CTA, tooltip, error, helper text, empty state, each with its own rule set.
Employee of the Month Recognised at Birdeye within 6 months of joining. Plugin cited directly.

This isn't just a portfolio piece

It's a working product used by a real design team. The skills it required span the full content design + engineering stack:

UX writing Content systems Prompt engineering TypeScript Figma Plugin API Deno / server-side JS REST API design AI/LLM integration Heuristic rule design Design system thinking VS Code · Cursor Content strategy

Content reviews were a bottleneck nobody talked about

At Birdeye, design moves fast. Designers finish a flow, need copy validated, and send a Slack message. The content designer reviews it async. Comments land in Figma hours later. Designers have moved on. Copy sometimes ships as-is.

The problem wasn't attention or intent. It was friction. Reviews happened outside the design tool, after the design was already done, in a format that required context-switching for everyone involved.

The best time to review copy is when a designer is looking at it, not six hours later in a comment thread.

I was already running content reviews manually. I knew the rules. I knew the patterns. And I knew that most of the errors I caught were the same ones, repeated across components, across teams. That's a system problem. Systems can be automated.


One panel. Three steps. Instant feedback.

The plugin lives inside Figma's plugin panel. A designer selects one or more text layers, picks the component type from a dropdown, and clicks Validate content. That's it.

Birdeye UXW Agent in Figma plugin menu
The plugin listed under Figma's plugin menu: accessible to the whole design team
Birdeye UXW Agent plugin UI
Plugin panel: component dropdown + validate CTA

The interface is intentionally minimal. The cognitive load belongs in the feedback, not the tool.


Same errors. Different designers. Every sprint.

After auditing three months of copy reviews, the failure modes were predictable:

Before
CTA: "Please submit your request"

Not imperative. Too long. Passive construction. No urgency.

After
CTA: "Submit request"

Verb-first. Concise. Action-oriented. Matches the design system.

Before
Error: "Invalid input."

What's invalid? Which field? What do I do? No context. No next step.

After
Error: "Enter a valid email address"

Specific. States the fix. Sentence case. No blame.

Before
Placeholder: "Please enter your email address here"

Instructions in a placeholder. Disappears on focus. Inaccessible.

After
Placeholder: "janesmith@example.com"

An example, not an instruction. Scannable. Accessible.

Before
Form hint: "ServiceNow entity"

Vague. No example. Users have no idea what to type or why.

After
Form hint: "Enter the ServiceNow item name you want to reference"

Specific. Actionable. Explains the what and the why.

These weren't judgment calls. They were rules. Rules that could be encoded, applied consistently, and returned in milliseconds.


Six layers. One continuous loop.

  1. Selection layer

    The plugin reads whichever text node a designer has selected via the Figma Plugin API, capturing the text, layer name, parent frame, sibling nodes, and page name as context signals.

  2. Semantic classification

    The designer picks a component type: CTA, tooltip, error message, helper text, empty state, placeholder, and 11 more. Each has a hardcoded ruleset with checks for length, voice, tone, structure, and punctuation.

  3. Prompt orchestration

    The selected text, component metadata, heuristic rules, and Birdeye's global style principles are compiled into a structured prompt. The model evaluates each check individually and returns structured JSON.

  4. Proxy / API layer

    Figma plugins can't store API keys safely client-side. I deployed a Deno proxy server that receives requests from the plugin, injects credentials securely, routes to the model, and normalises the response.

  5. AI evaluation

    The model returns: status (aligned or not aligned), a 0–100 quality score, which specific checks failed, an explanation, and suggested rewrites. Explore mode skips the verdict and returns 4–5 simpler alternatives.

  6. Canvas annotation rendering

    The JSON converts back into readable markdown and attaches to the selected Figma node as a native annotation. Designers see the feedback exactly where the copy lives, on the canvas itself.

Plugin open alongside a real Figma file being reviewed
Plugin open alongside a live design file: component type set to Toaster, ready to validate
Plugin showing validation in progress
Validation in progress: "Validating 1 / 2…" shows real-time status when multiple layers are selected
System architecture
🖱 Select text Figma canvas
⚙️ Plugin UI code.ts
🔗 Deno proxy server.ts
🤖 LLM OpenAI API
📝 Annotation Figma canvas

Heuristics, not hunches

Every component type has explicit checks derived from Birdeye's UX writing guidelines. These aren't suggestions, they're tests. The model evaluates each one pass/fail and the score reflects the ratio.

Component Checks run
CTA Starts with imperative verb · ≤3 words · no ending punctuation · no vague verbs like "Submit" or "OK"
Tooltip ≤120 characters · one sentence · explains why or how, not restating the label · no jargon
Error message States issue + context + next step · plain language · ≤90 chars · active voice · no blame
Form hint Short guidance or format rule · example where helpful · does not repeat the label · ≤90 chars
Toaster Confirms the result in one short sentence · friendly tone · no extra interaction required
Placeholder Example, not instruction · ≤5 words · no critical info · no period
Empty state Positive tone · one clear next step · benefit-oriented headline · no filler

Global checks apply across all components: US English, sentence case, active voice, contractions encouraged, no jargon.

// CTA validation heuristics, server.ts cta: `Checks: - Imperative verb first (e.g., "Save", "Update", "Send") - <= 3 words, very short and scannable - Strong, specific verb, no vague "Submit" or "OK" - No ending punctuation - Sentence case or Title Case per design system`

Strictness is configurable. Light mode allows up to 2 failed checks before returning "not aligned." Strict allows none. Teams dial up rigour depending on the surface, onboarding vs internal admin screens.


The result lives where the copy lives

When the plugin returns a result, it writes it as a native Figma annotation, attached directly to the selected text node on the canvas. Not in a side panel. Not in a comment thread. Exactly where the designer is already looking.

Figma canvas showing annotation attached to a toaster message
✅ Aligned result: annotation confirms "Your content aligns with the style guide" directly on the canvas node
Not aligned annotation with failed checks and rewrites
⚠ Not aligned result: shows score (50%), failed checks, and 3 suggested rewrites for the form hint component

The annotation format mirrors Figma's native Dev Mode annotation categories, Development, Interaction, Accessibility, and Content, so it integrates visually with how design teams already work.

Multiple aligned toaster annotations
Multiple layers validated at once: both return aligned results
Annotation category picker showing Content category
Annotations tagged under the "Content" category in Figma's native annotation system
Annotation visible alongside dev panel properties
Annotation sits alongside the dev panel: content feedback in the same workflow as token and spacing specs

What I built, and why

  1. Deno over Node for the proxy

    Deploys in seconds, built-in TypeScript, cold-start-fast on the free tier. For a plugin proxy handling bursts during design reviews, that mattered more than ecosystem size.

  2. Structured JSON output from the model

    I constrained output to a strict JSON schema using OpenAI's response_format: { type: "json_object" }. No regex. No parsing heuristics. Deterministic annotation rendering.

  3. Two modes: validate and explore

    Validate returns a pass/fail verdict with rewrites. Explore skips the verdict and returns 4–5 simpler alternatives. Designers told me they sometimes want options, not a grade.

  4. Context signals from surrounding layers

    The plugin reads parent frame name, sibling text nodes, page name, and layer name, all fed into the prompt. A CTA labelled "Save" inside a "Delete account" frame is different from the same word in onboarding.

  5. Consistency check across multiple selections

    When a designer selects more than one text node, the plugin checks them against each other, length, case, punctuation, voice, in addition to each against the style guide.


What changed

0 pings

Designers validate copy without contacting the content team for routine reviews.

16 rules

Component types covered, each with specific linguistic heuristics.

2 modes

Validate for verdicts. Explore for options. One tool, two intent states.

6 months

Time from joining Birdeye to Employee of the Month, plugin cited as a direct reason.

Beyond the numbers: this changed how content design was perceived at Birdeye. When a tool that automates expert judgment ships inside the design tool itself, content design stops being a bottleneck. It becomes infrastructure.


Content systems are software

The plugin didn't just automate a review task. It encoded years of UX writing judgment into something another person, or a whole design team, can access without me in the room. That's what a real content system does. It scales the author, not just the output.

Rishi Sharma · Lead Content Designer · Birdeye

Building this taught me the line between content design and product engineering is thinner than either discipline admits. The hard part wasn't the code, it was knowing what to check, how to phrase the rules, and what level of strictness serves a designer's intent without annoying them. That's a content problem wearing a developer costume.

The planned next version adds screenshot-based consistency checking: upload a production screen, compare new Figma copy against what's already live. Same architecture. New context layer.