Figma Plugin

Eluan Theme Builder generates the full design token variable set inside a Figma file, from one to three accent colors.

The plugin runs the same color engine as the CSS token pipeline — OKLCH scale generation, perceptual lightness curves, and WCAG contrast auto-correction — but writes its output as native Figma variables instead of CSS. Designers get the same palette the code consumes, with light and dark wired up as Figma modes.

Install

The plugin is not on the Figma Community yet, so it's installed from a local build. Clone the repo, build once, then import the manifest.

In the Figma desktop app, open Plugins → Development → Import plugin from manifest… and select manifest.json from the repo root. The plugin then appears as Eluan Theme Builder under your development plugins.

Use npm run watch while working on the plugin itself — Figma picks up rebuilt output when you re-run the plugin.

Generating a theme

Run the plugin on any Figma design file. The panel asks for two things:

  • Theme name — becomes the variable collection name. Defaults to custom.
  • Accent colors — one to three hex values. The first is the primary accent; the second and third become secondary and tertiary.

Scales and a contrast report preview live in the panel as you type. Nothing is written to the file until you press Generate Variables.

For distinguishable secondary and tertiary accents, pick hues at least 30° apart. Near-achromatic accents (very low chroma) produce scales that read as neutral grays.

What gets created

The plugin creates — or updates — a single variable collection named after your theme, containing two layers of variables.

Primitives are raw color values, named {scale}/{step} across the 11-step scale:

Semantic variables sit on top, named from the dotted token path with slashes so Figma groups them in the variables panel — action-primary.bg becomes action-primary/bg. Each semantic variable is a variable alias pointing at a primitive rather than a copied hex value, so editing a primitive propagates everywhere, exactly like the CSS layer.

Light and dark modes

The collection gets two Figma modes, Light and Dark. Every semantic variable is given a value in both: light maps to low scale steps for backgrounds and high steps for foregrounds, dark inverts that. Switching a frame between modes in Figma reproduces what data-mode does in CSS.

Primitives are mode-independent — they hold one value in the collection's first mode, and the semantic layer is what varies.

Contrast checking

Before generating, the panel shows a contrast report with Light and Dark tabs. It runs every foreground/background pairing in the semantic map against its required minimum — 4.5:1 for text, 3.0:1 for large text and UI components — and auto-corrects failing pairs by shifting scale steps. Pairs that still fail after correction are flagged so you can adjust the accent before writing variables.

Re-running the plugin

The plugin is idempotent. It looks up the collection, modes, and each variable by name and reuses them when they exist, creating them only when missing. Running it again with a tweaked accent updates values in place, so anything already bound to those variables in your designs stays bound.

Because matching is by name, renaming a generated collection or variable in Figma causes the next run to create a fresh one alongside it.

Network access

The manifest declares "networkAccess": { "allowedDomains": ["none"] }. All color math runs locally inside the plugin sandbox — no colors, tokens, or file contents leave your machine.