组件库做成变量 — Figma 插件 · 设计师自研工具A component library built as variants — Figma plugin · a designer-built tool
设计师给自己造的 Figma 插件:选一块规范 Frame,看一眼,点生成,组件集就按统一的属性体系建好了。它解决的是设计系统落地里最耗时、最容易乱的一段——把画好的样稿一个个变成带变体、带属性、命名一致的组件。我负责定义问题、设计规则和验收标准,与 AI 编程协作完成实现,并在真实文件里跑通。 A Figma plugin I built for my own workflow: select a spec frame, glance, generate — and the component set is built on one consistent property system. It targets the slowest, messiest stretch of shipping a design system: turning drawn samples into variant components with consistent names. I defined the problem, the rules and the acceptance criteria, built it with AI-assisted coding, and verified it in a live file.
设计系统的瓶颈往往不在画,而在把画好的东西变成可复用的组件:一个个 Create component、Combine as variants、手填属性名和值。状态会漏,命名会乱,每个人一套叫法,规范一改又得重做。后面的页面搭建和开发对接,都卡在这一段。The bottleneck of a design system is rarely the drawing. It is turning what is drawn into reusable components: Create component, Combine as variants, type property names and values, one by one. States get missed, names drift, everyone has their own vocabulary, and a spec change means redoing it. Page assembly and developer handoff both stall here.
几十个样稿逐个建变体、填属性,一下午过去了,还没到对接。Dozens of samples, each turned into a variant by hand. An afternoon gone before any handoff.
Type、Theme、Status 各叫各的,同一个意思三种属性名,页面生成和代码都对不上。Type, Theme and Status all mean the same thing in different files. Page generation and code cannot line up with any of them.
hover、禁用靠记忆补,补出来的和规范对不上;嵌套实例一解除,样子就变了。Hover and disabled are filled from memory and disagree with the spec. Detach a nested instance and the look changes.
插件不替设计师做决定,而是把我们每次手搭组件时默默在做的判断写下来:这块叫什么、哪个颜色代表什么、深浅是不是状态、哪些组合不该补。规则对照开源组件库定下来,推断的地方标出来可核,原稿永远不动。The plugin does not decide for the designer. It writes down the judgments we silently make every time we build a component by hand: what this block is called, what each colour means, whether a shade is a state, which combinations must never be invented. The rules are aligned with open-source component libraries, every inference is visible and checkable, and the original drawings are never touched.
标题、说明、标注文字是依据:「Tag 标签」认出家族,「默认 24」定默认尺寸,「hover」「禁用」定状态。说明文字只当依据,不画进组件。Headings, descriptions and annotations are evidence: “Tag” names the family, “default 24” sets the default size, “hover” and “disabled” set states. Descriptive text is read, never drawn into the component.
Color / Style / Shape / Size / Checked / State,对照 Ant Design、TDesign、Arco、Element Plus、Semi 定下来。旧文件里的 Type、Theme、Status 自动归位。Color / Style / Shape / Size / Checked / State, aligned with Ant Design, TDesign, Arco, Element Plus and Semi. Legacy Type, Theme and Status names map onto it automatically.
按惯例猜的地方(深浅当 hover、红色当 Danger)单独列出来,点一下就在画布里选中对应样稿;不看也能生成。State 和 Checked 永远不凭空补。Convention-based guesses (lighter shade = hover, red = Danger) are listed separately; one click selects the source sample on the canvas. You can generate without reading them. State and Checked are never invented.
原稿页只读,失败全部清理,生成后自查属性可读、变体名不重、外观一致、颜色对值。核对不等于验收——最后一眼还是设计师的。Source pages are read-only, failures are fully cleaned up, and after generation the plugin checks that properties read, variant names are unique, looks match and colours match values. Self-check is not acceptance: the final look is still the designer's.
右边是插件面板的模拟,会自己打字、勾选、点按钮,和 Figma 里是同一套界面。点左侧任一步单看,也可以让它自动播。On the right is a simulation of the plugin panel: it types, ticks and clicks by itself, mirroring the real interface in Figma (panel text is in Chinese, as in the plugin). Click any step on the left, or let it play.
Figma 变体属性名就是用途。属性名对照 Ant Design、TDesign、Arco、Element Plus、Semi 定下来,不同文件、不同人做出来的组件集长一样;旧文件里的 Type、Theme、Status 自动当 Color,Variant、Effect 当 Style。A variant property name is its purpose. Names are aligned with Ant Design, TDesign, Arco, Element Plus and Semi, so component sets built by different people in different files look the same. Legacy Type, Theme and Status map to Color; Variant and Effect map to Style.
颜色代表什么,不是什么色。先按规范里的颜色文字分簇,再按色相兜底;红色当 Danger 这类推断会标出来。Tag 另有一套预设色名。What a colour means, not what hue it is. Clustered first by the colour words in the spec, then by hue as a fallback; guesses such as red = Danger are flagged. Tag has its own preset palette names.
同一个颜色怎么画:实底、浅底深字、描边、虚线、纯文字、链接。浅底只在文字是彩色时才算 Light,灰按钮不会误判。How the same colour is drawn: solid, pale fill with coloured text, outline, dashed, text only, link. A pale fill only counts as Light when the text is chromatic, so grey buttons are not misread.
由圆角和宽高比决定。只有同一组里真的出现了不同形状才会生成这个属性。Decided by corner radius and aspect ratio. The property is only created when different shapes really appear in the same group.
按高度分档。规范写了「默认 24」就用 24 当默认;值名可以在「逐步调整」里切成语义名或数值。Bucketed by height. If the spec says “default 24”, 24 is the default; value names can be switched between semantic and numeric in step-by-step mode.
Switch 看滑块在哪边,Checkbox 看勾、横线、点,Radio 不允许 Indeterminate。能被 Checked 解释的颜色差异不会再多生成一个 Color。Switch reads the knob side; Checkbox reads tick, dash or dot; Radio never gets Indeterminate. A colour difference explained by Checked does not spawn an extra Color value.
多数样稿的深浅是 Default;彩色里更浅是 Hover、发白是 Disabled、更深是 Pressed;转圈是 Loading。只读标注,不凭空补。The majority shade is Default; among chromatic samples lighter is Hover, washed-out is Disabled, darker is Pressed; a spinner is Loading. Read from annotations, never invented.
组件化只是上半场。第二个插件 Page From System 读这些组件集,按需求表单拼出后台列表页;两个插件之间靠存进文件的规则对接。设计师的时间从「搭」挪到「定规则、看结果」。Componentizing is only the first half. A second plugin, Page From System, reads these component sets and assembles admin list pages from a requirements form; the two connect through rules stored in the file. The designer's time moves from building to setting rules and reviewing results.
把规范页的散件做成 Button、Input、Select、Tag 这些组件集,并把确认过的属性名、值名、默认值和放置位置存进文件。Turns the spec page into Button, Input, Select, Tag component sets, and stores the confirmed names, values, defaults and placement in the file.
按需求表单登记每个位置用哪个组件、哪组变体、文字写进哪个属性,拼出后台列表页。生成前自动存版本点。A requirements form registers which component, variants and text property each slot uses, then assembles an admin list page. A version checkpoint is saved first.
结果页拿组件化存的规则检查页面:每个实例的组件集是否登记过、Variable 是否绑定、有没有超出父容器。点一项就在画布里选中。The result page checks the page against the stored rules: is every instance's set registered, are Variables bound, does anything overflow its parent. One click selects the node.
这个项目里我没有写代码,但每一条规则、每一个按钮的文案、每一次「这个不对」的打回,都是设计师的工作。它展示的是:能把一段工作流拆解成可执行的规则,能定义验收标准并在真实文件里验证,能和 AI 一起把工具做出来、交给别人用。I did not write the code in this project, but every rule, every button label and every “this is wrong” rejection was design work. What it shows: the ability to break a workflow into executable rules, to define acceptance criteria and verify them in a live file, and to build and hand over a tool together with AI.
把一个设计系统拆成家族、属性、状态、命名、分区、放置位置几件独立的事,每件只管一件,所以 Tag 和 Button 能用同一套规则生成。A design system broken into independent concerns — family, properties, states, naming, sections, placement — each doing one job, so Tag and Button generate from the same rules.
「手搭组件时在想什么」被写成了可执行、可导出、别人也能用的规则,而不是一次性的脚本或只有我会的流程。“What I think about while hand-building components” became executable, exportable rules that others can use — not a one-off script or a process only I know.
我负责问题定义、规则、验收标准和实机测试;代码由 AI 编程协作完成。本地测试通过不算完成,真实文件里跑通、逐个状态看过才算。I owned the problem definition, rules, acceptance criteria and live testing; the code was written with AI coding partners. Passing local tests is not done — running in a real file and checking every state is.
知道 Figma 不允许同一组件集属性不一致、嵌套实例一解除就会变样、插件驱动不了文件对话框——所以流程里给的是可点的办法,而不是一句报错。Knowing that Figma forbids mismatched properties in one set, that detaching nested instances changes the look, that a plugin cannot drive file dialogs — so the flow offers clickable fixes instead of error messages.
Figma 不允许同一组件集里的变体属性不一样。点「换名新建『X 新版』」最省事,旧的不动,插件会按新属性体系重新推断;或者「去掉多出的属性」只往旧的里加变体。Figma does not allow mismatched variant properties in one set. “Create as ‘X 新版’” is the easy path: the old set stays, the plugin re-infers on the new system. Or “drop the extra property” to only add variants to the old set.
样稿本身是别的组件的实例时,插件默认不解除、整个嵌进去,所以 Label 接不到里面的文字。到规则页打开「解除实例」再生成一次。When samples are instances of other components, they are nested rather than detached by default, so Label cannot reach the text inside. Turn on “Detach instances” on the rules page and generate again.
一块规范 Frame 出一个组件集,别把 Tag 和 Button 一起选。真混进来了就在确认页点「逐步调整」,到「分组」步用文字 chips 成批勾掉。One spec frame makes one component set; do not select Tag and Button together. If something slipped in, click “Step by step” on Confirm and untick by text chips in the Group step.
可以不看。里面是按惯例猜的地方:深浅当 hover、红色当 Danger、灰色当 Default。想核对就点开,每条都有「看」按钮在画布里选中对应样稿。Not necessarily. It lists convention-based guesses: shade as hover, red as Danger, grey as Default. Open it to check; each line has a “view” button that selects the sample on the canvas.
这个组件集在 Figma 里有报错(选中它看右栏会有红字),多半是变体组合重复或缺值。页面生成会改从变体名推断属性仍能生成;但根子要回到自动组件化里把组件集修好。That set has an error in Figma (select it and the right panel shows red text), usually duplicate or missing variant combinations. Page generation falls back to reading variant names; the real fix is repairing the set in Auto Componentize.
组件集里没有完全匹配的变体时,页面生成按 Color、Style、State、Size 的优先级取最接近的,并在「结果」页第一屏写明差了哪个值。补上缺的变体再重新生成即可。When no exact variant exists, page generation picks the closest by Color, Style, State, Size priority and states the difference on the result page. Add the missing variant and regenerate.
说明它的结构和生成时存的签名不一样,插件判定你手动改过。要重做就手动勾上它;被替换的旧模块不会删,移到同页的「页面生成·历史」Section。Its structure no longer matches the signature stored at generation, so the plugin treats it as hand-edited. Tick it manually to redo; replaced modules are moved to the “Page generation · history” section, never deleted.