@fprad0/skill-master-mcp 0.0.12 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (331) hide show
  1. package/CHANGELOG.md +96 -90
  2. package/README.md +472 -472
  3. package/VERSION.md +9 -9
  4. package/bin/lib/bootstrap-global-core.mjs +34 -0
  5. package/bin/lib/client-config.mjs +293 -293
  6. package/bin/lib/doctor-core.mjs +202 -0
  7. package/bin/lib/menu-core.mjs +1629 -1522
  8. package/bin/lib/operation-result.mjs +59 -0
  9. package/bin/lib/register-clients-core.mjs +247 -0
  10. package/bin/lib/skill-installation.mjs +215 -215
  11. package/bin/lib/update-cli-core.mjs +117 -0
  12. package/bin/skill-master-activation.mjs +163 -163
  13. package/bin/skill-master-bootstrap-global.mjs +61 -49
  14. package/bin/skill-master-configure-private-registry.mjs +3 -3
  15. package/bin/skill-master-doctor.mjs +239 -228
  16. package/bin/skill-master-eval-activation.mjs +32 -32
  17. package/bin/skill-master-install-global-skills.mjs +59 -59
  18. package/bin/skill-master-install-project-skills.mjs +97 -97
  19. package/bin/skill-master-menu.mjs +406 -405
  20. package/bin/skill-master-register-clients.mjs +232 -153
  21. package/bin/skill-master-success-skills.mjs +307 -307
  22. package/bin/skill-master-update.mjs +121 -72
  23. package/bin/skill-master.mjs +3 -3
  24. package/dist/activation.d.ts.map +1 -1
  25. package/dist/activation.js +12 -0
  26. package/dist/activation.js.map +1 -1
  27. package/dist/prompt-router.d.ts.map +1 -1
  28. package/dist/prompt-router.js +19 -0
  29. package/dist/prompt-router.js.map +1 -1
  30. package/dist/recommender.d.ts.map +1 -1
  31. package/dist/recommender.js +4 -1
  32. package/dist/recommender.js.map +1 -1
  33. package/docs/architecture/APRENDIZADO_DE_IMPLEMENTACOES_BEM_SUCEDIDAS.md +125 -125
  34. package/docs/architecture/ARQUITETURA_AUTO_UPDATE.md +9 -9
  35. package/docs/architecture/PLANO_MASTER_ACIONAMENTO_AUTOMATICO_E_APRENDIZADO.md +341 -341
  36. package/docs/architecture/REDE_SEGURA_DE_SKILLS.md +148 -148
  37. package/docs/operations/GUIA_MULTI_COMPUTADOR.md +262 -262
  38. package/docs/operations/GUIA_NPM_PRIVADO.md +294 -294
  39. package/docs/operations/GUIA_NPM_PUBLICO.md +147 -147
  40. package/docs/operations/MENU_VISUAL_EVIDENCE_2026-06-28.md +66 -66
  41. package/docs/operations/assets/menu-frame-compact.html +75 -75
  42. package/docs/operations/assets/menu-frame-large.html +83 -83
  43. package/docs/operations/assets/menu-frame-running.html +79 -79
  44. package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -140
  45. package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -85
  46. package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -174
  47. package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -119
  48. package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -134
  49. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -84
  50. package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -56
  51. package/docs/operations/token-economy-transfer/ANALISE_AVANCADA_ECONOMIA_TOKENS_2026-06-30.md +141 -0
  52. package/docs/operations/token-economy-transfer/PLANO_DEV_SENIOR_MASTER_TOKEN_ECONOMY_2026-06-30.md +171 -0
  53. package/docs/operations/token-economy-transfer/README_TRANSFERENCIA_TOKEN_ECONOMY.md +31 -0
  54. package/docs/planning/MENU_RUNTIME_CORRECTION_PLAN_2026-06-30.md +551 -0
  55. package/docs/planning/V0_0_9_APROVACAO_CRITICA_MENSAGENS_DE_VENDA.md +85 -85
  56. package/docs/planning/V0_0_9_FONTES_E_CRITERIOS_DE_AUTORIDADE.md +139 -139
  57. package/docs/planning/V0_0_9_MATRIZ_SKILLS_MULTIDISCIPLINARES.md +105 -105
  58. package/docs/planning/V0_0_9_POLITICA_MORAL_CATOLICA_PARA_IA.md +181 -181
  59. package/docs/planning/V0_0_9_PROMPTS_EXECUCAO.md +59 -59
  60. package/docs/planning/V0_0_9_ROADMAP_DISCERNIMENTO_E_CONHECIMENTO_AMPLO.md +181 -181
  61. package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -6
  62. package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -6
  63. package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -6
  64. package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -6
  65. package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -6
  66. package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -83
  67. package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -88
  68. package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -156
  69. package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -105
  70. package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -119
  71. package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -120
  72. package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -123
  73. package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -114
  74. package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -157
  75. package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -127
  76. package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -107
  77. package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -80
  78. package/docs/prompt-tasks/PROMPT_TASK_019_TOKEN_ECONOMY_GLOBAL_SKILLS.md +56 -0
  79. package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -6
  80. package/docs/skill-candidates/v0.0.10/cli-creator/LICENSE.txt +201 -201
  81. package/docs/skill-candidates/v0.0.10/cli-creator/SKILL.md +160 -160
  82. package/docs/skill-candidates/v0.0.10/cli-creator/agents/openai.yaml +4 -4
  83. package/docs/skill-candidates/v0.0.10/cli-creator/references/agent-cli-patterns.md +154 -154
  84. package/docs/skill-candidates/v0.0.10/developer-workstation-ops/SKILL.md +32 -32
  85. package/docs/skill-candidates/v0.0.10/figma/LICENSE.txt +1 -1
  86. package/docs/skill-candidates/v0.0.10/figma/SKILL.md +42 -42
  87. package/docs/skill-candidates/v0.0.10/figma/agents/openai.yaml +14 -14
  88. package/docs/skill-candidates/v0.0.10/figma/assets/figma-small.svg +3 -3
  89. package/docs/skill-candidates/v0.0.10/figma/assets/icon.svg +28 -28
  90. package/docs/skill-candidates/v0.0.10/figma/references/figma-mcp-config.md +35 -35
  91. package/docs/skill-candidates/v0.0.10/figma/references/figma-tools-and-prompts.md +34 -34
  92. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/LICENSE.TXT +1 -1
  93. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/SKILL.md +349 -349
  94. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/agents/openai.yaml +14 -14
  95. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma-small.svg +3 -3
  96. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/icon.svg +28 -28
  97. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/references/mapping-checklist.md +7 -7
  98. package/docs/skill-candidates/v0.0.10/figma-code-connect-components/scripts/normalize_node_id.py +25 -25
  99. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/LICENSE.TXT +1 -1
  100. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/SKILL.md +537 -537
  101. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/agents/openai.yaml +14 -14
  102. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma-small.svg +3 -3
  103. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/icon.svg +28 -28
  104. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/references/rule-template.md +15 -15
  105. package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -9
  106. package/docs/skill-candidates/v0.0.10/figma-generate-design/LICENSE.TXT +1 -1
  107. package/docs/skill-candidates/v0.0.10/figma-generate-design/SKILL.md +341 -341
  108. package/docs/skill-candidates/v0.0.10/figma-generate-design/agents/openai.yaml +14 -14
  109. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma-small.svg +3 -3
  110. package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/icon.svg +28 -28
  111. package/docs/skill-candidates/v0.0.10/figma-generate-design/maintainers.yml +1 -1
  112. package/docs/skill-candidates/v0.0.10/figma-generate-library/LICENSE.TXT +1 -1
  113. package/docs/skill-candidates/v0.0.10/figma-generate-library/SKILL.md +314 -314
  114. package/docs/skill-candidates/v0.0.10/figma-generate-library/agents/openai.yaml +14 -14
  115. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma-small.svg +3 -3
  116. package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/icon.svg +28 -28
  117. package/docs/skill-candidates/v0.0.10/figma-generate-library/maintainers.yml +3 -3
  118. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/code-connect-setup.md +260 -260
  119. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/component-creation.md +1014 -1014
  120. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/discovery-phase.md +518 -518
  121. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/documentation-creation.md +834 -834
  122. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/error-recovery.md +540 -540
  123. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/naming-conventions.md +527 -527
  124. package/docs/skill-candidates/v0.0.10/figma-generate-library/references/token-creation.md +962 -962
  125. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js +110 -110
  126. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/cleanupOrphans.js +127 -127
  127. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js +148 -148
  128. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js +139 -139
  129. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createSemanticTokens.js +108 -108
  130. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js +49 -49
  131. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/inspectFileStructure.js +121 -121
  132. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/rehydrateState.js +92 -92
  133. package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/validateCreation.js +83 -83
  134. package/docs/skill-candidates/v0.0.10/figma-implement-design/LICENSE.txt +1 -1
  135. package/docs/skill-candidates/v0.0.10/figma-implement-design/SKILL.md +258 -258
  136. package/docs/skill-candidates/v0.0.10/figma-implement-design/agents/openai.yaml +14 -14
  137. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma-small.svg +3 -3
  138. package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/icon.svg +28 -28
  139. package/docs/skill-candidates/v0.0.10/figma-use/LICENSE.TXT +1 -1
  140. package/docs/skill-candidates/v0.0.10/figma-use/SKILL.md +233 -233
  141. package/docs/skill-candidates/v0.0.10/figma-use/agents/openai.yaml +14 -14
  142. package/docs/skill-candidates/v0.0.10/figma-use/assets/figma-small.svg +3 -3
  143. package/docs/skill-candidates/v0.0.10/figma-use/assets/icon.svg +28 -28
  144. package/docs/skill-candidates/v0.0.10/figma-use/maintainers.yml +1 -1
  145. package/docs/skill-candidates/v0.0.10/figma-use/references/api-reference.md +301 -301
  146. package/docs/skill-candidates/v0.0.10/figma-use/references/common-patterns.md +512 -512
  147. package/docs/skill-candidates/v0.0.10/figma-use/references/component-patterns.md +488 -488
  148. package/docs/skill-candidates/v0.0.10/figma-use/references/effect-style-patterns.md +123 -123
  149. package/docs/skill-candidates/v0.0.10/figma-use/references/gotchas.md +599 -599
  150. package/docs/skill-candidates/v0.0.10/figma-use/references/maintainers.yml +12 -12
  151. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-patterns.md +513 -513
  152. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.d.ts +11293 -11293
  153. package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.index.md +441 -441
  154. package/docs/skill-candidates/v0.0.10/figma-use/references/text-style-patterns.md +203 -203
  155. package/docs/skill-candidates/v0.0.10/figma-use/references/validation-and-recovery.md +109 -109
  156. package/docs/skill-candidates/v0.0.10/figma-use/references/variable-patterns.md +354 -354
  157. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/maintainers.yml +9 -9
  158. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--creating.md +17 -17
  159. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--using.md +17 -17
  160. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components.md +50 -50
  161. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-effect-styles.md +52 -52
  162. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-text-styles.md +90 -90
  163. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--creating.md +13 -13
  164. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--using.md +13 -13
  165. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables.md +64 -64
  166. package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds.md +41 -41
  167. package/docs/skill-candidates/v0.0.10/frontend-design/LICENSE.txt +177 -177
  168. package/docs/skill-candidates/v0.0.10/frontend-design/SKILL.md +55 -55
  169. package/docs/skill-candidates/v0.0.10/frontend-ui-ux-systems/SKILL.md +32 -32
  170. package/docs/skill-candidates/v0.0.10/github/SKILL.md +74 -74
  171. package/docs/skill-candidates/v0.0.10/github/agents/openai.yaml +6 -6
  172. package/docs/skill-candidates/v0.0.10/github/assets/github-small.svg +3 -3
  173. package/docs/skill-candidates/v0.0.10/image-graphic-design-rendering/SKILL.md +28 -28
  174. package/docs/skill-candidates/v0.0.10/language-quality-pt-en-fr-it-ru/SKILL.md +28 -28
  175. package/docs/skill-candidates/v0.0.10/math-physics-reasoning/SKILL.md +28 -28
  176. package/docs/skill-candidates/v0.0.10/mcp-builder/LICENSE.txt +201 -201
  177. package/docs/skill-candidates/v0.0.10/mcp-builder/SKILL.md +236 -236
  178. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/evaluation.md +601 -601
  179. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/mcp_best_practices.md +249 -249
  180. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/node_mcp_server.md +969 -969
  181. package/docs/skill-candidates/v0.0.10/mcp-builder/reference/python_mcp_server.md +718 -718
  182. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/connections.py +151 -151
  183. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/evaluation.py +373 -373
  184. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/example_evaluation.xml +22 -22
  185. package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/requirements.txt +2 -2
  186. package/docs/skill-candidates/v0.0.10/mcp-client-readiness/SKILL.md +31 -31
  187. package/docs/skill-candidates/v0.0.10/openai-docs/LICENSE.txt +201 -201
  188. package/docs/skill-candidates/v0.0.10/openai-docs/SKILL.md +161 -161
  189. package/docs/skill-candidates/v0.0.10/openai-docs/agents/openai.yaml +14 -14
  190. package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai-small.svg +3 -3
  191. package/docs/skill-candidates/v0.0.10/openai-docs/references/latest-model.md +37 -37
  192. package/docs/skill-candidates/v0.0.10/openai-docs/references/prompting-guide.md +244 -244
  193. package/docs/skill-candidates/v0.0.10/openai-docs/references/upgrade-guide.md +181 -181
  194. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/fetch-codex-manual.mjs +598 -598
  195. package/docs/skill-candidates/v0.0.10/openai-docs/scripts/resolve-latest-model-info.js +147 -147
  196. package/docs/skill-candidates/v0.0.10/playwright/NOTICE.txt +14 -14
  197. package/docs/skill-candidates/v0.0.10/playwright/SKILL.md +147 -147
  198. package/docs/skill-candidates/v0.0.10/playwright/agents/openai.yaml +6 -6
  199. package/docs/skill-candidates/v0.0.10/playwright/assets/playwright-small.svg +3 -3
  200. package/docs/skill-candidates/v0.0.10/playwright/references/cli.md +116 -116
  201. package/docs/skill-candidates/v0.0.10/playwright/references/workflows.md +95 -95
  202. package/docs/skill-candidates/v0.0.10/playwright/scripts/playwright_cli.sh +25 -25
  203. package/docs/skill-candidates/v0.0.10/polyglot-backend-engineering/SKILL.md +32 -32
  204. package/docs/skill-candidates/v0.0.10/screenshot/LICENSE.txt +201 -201
  205. package/docs/skill-candidates/v0.0.10/screenshot/SKILL.md +267 -267
  206. package/docs/skill-candidates/v0.0.10/screenshot/agents/openai.yaml +6 -6
  207. package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot-small.svg +5 -5
  208. package/docs/skill-candidates/v0.0.10/screenshot/scripts/ensure_macos_permissions.sh +54 -54
  209. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_display_info.swift +22 -22
  210. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_permissions.swift +40 -40
  211. package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_window_info.swift +126 -126
  212. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.ps1 +163 -163
  213. package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.py +585 -585
  214. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/SKILL.md +62 -62
  215. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/agents/openai.yaml +4 -4
  216. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/activation-policy.md +77 -77
  217. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/human-approval-policy.md +83 -83
  218. package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/persona-dev-senior-master.md +46 -46
  219. package/docs/skill-candidates/v0.0.10/terminal-menu-operations/SKILL.md +30 -30
  220. package/docs/skill-candidates/v0.0.10/terminal-pixel-art-tui/SKILL.md +43 -43
  221. package/docs/skill-candidates/v0.0.10/webapp-testing/LICENSE.txt +201 -201
  222. package/docs/skill-candidates/v0.0.10/webapp-testing/SKILL.md +95 -95
  223. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/console_logging.py +34 -34
  224. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/element_discovery.py +39 -39
  225. package/docs/skill-candidates/v0.0.10/webapp-testing/examples/static_html_automation.py +32 -32
  226. package/docs/skill-candidates/v0.0.10/webapp-testing/scripts/with_server.py +105 -105
  227. package/docs/skill-candidates/v0.0.10/winui-app/LICENSE.txt +201 -201
  228. package/docs/skill-candidates/v0.0.10/winui-app/SKILL.md +94 -94
  229. package/docs/skill-candidates/v0.0.10/winui-app/agents/openai.yaml +5 -5
  230. package/docs/skill-candidates/v0.0.10/winui-app/config.yaml +50 -50
  231. package/docs/skill-candidates/v0.0.10/winui-app/references/_sections.md +96 -96
  232. package/docs/skill-candidates/v0.0.10/winui-app/references/accessibility-input-and-localization.md +51 -51
  233. package/docs/skill-candidates/v0.0.10/winui-app/references/build-run-and-launch-verification.md +72 -72
  234. package/docs/skill-candidates/v0.0.10/winui-app/references/community-toolkit-controls-and-helpers.md +57 -57
  235. package/docs/skill-candidates/v0.0.10/winui-app/references/controls-layout-and-adaptive-ui.md +84 -84
  236. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-environment-audit-and-remediation.md +82 -82
  237. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-setup-and-project-selection.md +67 -67
  238. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-template-first-recovery.md +62 -62
  239. package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-winui-app-structure.md +62 -62
  240. package/docs/skill-candidates/v0.0.10/winui-app/references/motion-animations-and-polish.md +45 -45
  241. package/docs/skill-candidates/v0.0.10/winui-app/references/performance-diagnostics-and-responsiveness.md +46 -46
  242. package/docs/skill-candidates/v0.0.10/winui-app/references/sample-source-map.md +37 -37
  243. package/docs/skill-candidates/v0.0.10/winui-app/references/shell-navigation-and-windowing.md +67 -67
  244. package/docs/skill-candidates/v0.0.10/winui-app/references/styling-theming-materials-and-icons.md +71 -71
  245. package/docs/skill-candidates/v0.0.10/winui-app/references/testing-debugging-and-review-checklists.md +77 -77
  246. package/docs/skill-candidates/v0.0.10/winui-app/references/windows-app-sdk-lifecycle-notifications-and-deployment.md +52 -52
  247. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +398 -398
  248. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +330 -330
  249. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +871 -871
  250. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +501 -501
  251. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +766 -766
  252. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +501 -501
  253. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +500 -500
  254. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +405 -405
  255. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +363 -363
  256. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +427 -427
  257. package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +417 -417
  258. package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -34
  259. package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -34
  260. package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -34
  261. package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -34
  262. package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -34
  263. package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -36
  264. package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -745
  265. package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -3
  266. package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -94
  267. package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -34
  268. package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -34
  269. package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -209
  270. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -103
  271. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -103
  272. package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -103
  273. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -114
  274. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -114
  275. package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -114
  276. package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -573
  277. package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -3
  278. package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -34
  279. package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -34
  280. package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -429
  281. package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +91 -91
  282. package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -383
  283. package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -335
  284. package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -203
  285. package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -34
  286. package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -34
  287. package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -34
  288. package/docs/skill-candidates/v0.0.12/context-compression-handoff/SKILL.md +47 -0
  289. package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -32
  290. package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -32
  291. package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -32
  292. package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -32
  293. package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -32
  294. package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -32
  295. package/docs/skill-candidates/v0.0.12/prompt-budget-gate/SKILL.md +46 -0
  296. package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -32
  297. package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -32
  298. package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -32
  299. package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -48
  300. package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -31
  301. package/docs/skill-candidates/v0.0.12/token-economy-orchestrator/SKILL.md +38 -0
  302. package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -35
  303. package/docs/skill-candidates/v0.0.9/ai-ethics-human-dignity/SKILL.md +32 -32
  304. package/docs/skill-candidates/v0.0.9/broad-domain-router/SKILL.md +41 -41
  305. package/docs/skill-candidates/v0.0.9/catholic-moral-discernment/SKILL.md +31 -31
  306. package/docs/skill-candidates/v0.0.9/engineering-systems-master/SKILL.md +31 -31
  307. package/docs/skill-candidates/v0.0.9/language-quality-pt-en-fr/SKILL.md +28 -28
  308. package/docs/skill-candidates/v0.0.9/math-science-reasoning/SKILL.md +29 -29
  309. package/docs/skill-candidates/v0.0.9/philosophy-sociology-discernment/SKILL.md +28 -28
  310. package/docs/skill-candidates/v0.0.9/professional-boundary-triage/SKILL.md +40 -40
  311. package/docs/skill-candidates/v0.0.9/release-ethics-gate/SKILL.md +32 -32
  312. package/docs/skill-candidates/v0.0.9/source-authority-reviewer/SKILL.md +31 -31
  313. package/examples/client-configs/claude-code.commands.md +21 -21
  314. package/examples/client-configs/claude-code.project.mcp.json +18 -18
  315. package/examples/client-configs/claude-desktop.macos.json +18 -18
  316. package/examples/client-configs/claude-desktop.windows.json +20 -20
  317. package/examples/client-configs/codex.windows.toml +11 -11
  318. package/examples/client-configs/gemini-code-assist.intellij.mcp.json +18 -18
  319. package/examples/client-configs/gemini.linux.settings.json +21 -21
  320. package/examples/client-configs/gemini.windows.settings.json +23 -23
  321. package/examples/client-configs/generic-stdio.json +16 -16
  322. package/manifests/channels/beta.json +26 -26
  323. package/manifests/channels/stable.json +27 -27
  324. package/network/approved-skills.json +54 -54
  325. package/network/unapproved-skill-candidates.json +110 -110
  326. package/package.json +87 -86
  327. package/scripts/configure-private-registry.mjs +208 -208
  328. package/scripts/lib/private-registry.mjs +97 -97
  329. package/scripts/render-menu-evidence.mjs +130 -130
  330. package/scripts/verify-menu-actions.mjs +117 -117
  331. package/sources.json +11 -11
@@ -1,599 +1,599 @@
1
- # Gotchas & Common Mistakes
2
-
3
- > Part of the [use_figma skill](../SKILL.md). Every known pitfall with WRONG/CORRECT code examples.
4
-
5
- ## Contents
6
-
7
- - Component properties and variant creation pitfalls
8
- - Paint, color, and variable binding pitfalls
9
- - Page context and plugin lifecycle pitfalls
10
- - Auto Layout and sizing order pitfalls (including HUG/FILL interactions)
11
- - Variant layout and geometry pitfalls
12
- - Variable scopes and mode pitfalls
13
- - Node cleanup and empty-fill pitfalls
14
- - detachInstance() and node ID invalidation
15
-
16
-
17
- ## New nodes default to (0,0) and overlap existing content
18
-
19
- Every `figma.create*()` call places the node at position (0,0). If you append multiple nodes directly to the page, they all stack on top of each other and on top of any existing content.
20
-
21
- **This only matters for nodes appended directly to the page** (i.e., top-level nodes). Nodes appended as children of other frames, components, or auto-layout containers are positioned by their parent — don't scan for overlaps when nesting nodes.
22
-
23
- ```js
24
- // WRONG — top-level node lands at (0,0), overlapping existing page content
25
- const frame = figma.createFrame()
26
- frame.name = "My New Frame"
27
- frame.resize(400, 300)
28
- figma.currentPage.appendChild(frame)
29
-
30
- // CORRECT — find existing content bounds and place the new top-level node to the right
31
- const page = figma.currentPage
32
- let maxX = 0
33
- for (const child of page.children) {
34
- const right = child.x + child.width
35
- if (right > maxX) maxX = right
36
- }
37
- const frame = figma.createFrame()
38
- frame.name = "My New Frame"
39
- frame.resize(400, 300)
40
- figma.currentPage.appendChild(frame)
41
- frame.x = maxX + 100 // 100px gap from rightmost existing content
42
- frame.y = 0
43
-
44
- // NOT NEEDED — child nodes inside a parent don't need overlap scanning
45
- const card = figma.createFrame()
46
- card.layoutMode = 'VERTICAL'
47
- const label = figma.createText()
48
- card.appendChild(label) // positioned by auto-layout, no x/y needed
49
- ```
50
-
51
- ## `addComponentProperty` returns a string key, not an object — never hardcode or guess it
52
-
53
- Figma generates the property key dynamically (e.g. `"label#4:0"`). The suffix is unpredictable. Always capture and use the return value directly.
54
-
55
- ```js
56
- // WRONG — guessing / hardcoding the key
57
- comp.addComponentProperty('label', 'TEXT', 'Button')
58
- labelNode.componentPropertyReferences = { characters: 'label#0:1' } // Error: key not found
59
-
60
- // WRONG — treating the return value as an object
61
- const result = comp.addComponentProperty('Label', 'TEXT', 'Button')
62
- const propKey = Object.keys(result)[0] // BUG: returns '0' (first char index of string!)
63
- labelNode.componentPropertyReferences = { characters: propKey } // Error: property '0' not found
64
-
65
- // CORRECT — the return value IS the key string, use it directly
66
- const propKey = comp.addComponentProperty('Label', 'TEXT', 'Button')
67
- // propKey === "label#4:0" (exact value varies; never assume it)
68
- labelNode.componentPropertyReferences = { characters: propKey }
69
- ```
70
-
71
- The same applies to `COMPONENT_SET` nodes — `addComponentProperty` always returns the property key as a string.
72
-
73
- ## MUST return ALL created/mutated node IDs
74
-
75
- Every script that creates or mutates nodes on the canvas must track and return all affected node IDs in the `figma.closePlugin()` response. Without these IDs, subsequent calls cannot reference, validate, or clean up those nodes.
76
-
77
- ```js
78
- // WRONG — only returns the parent frame ID, loses track of children
79
- const frame = figma.createFrame()
80
- const rect = figma.createRectangle()
81
- const text = figma.createText()
82
- frame.appendChild(rect)
83
- frame.appendChild(text)
84
- figma.closePlugin(JSON.stringify({ nodeId: frame.id }))
85
-
86
- // CORRECT — returns all created node IDs in a structured response
87
- const frame = figma.createFrame()
88
- const rect = figma.createRectangle()
89
- const text = figma.createText()
90
- frame.appendChild(rect)
91
- frame.appendChild(text)
92
- figma.closePlugin(JSON.stringify({
93
- createdNodeIds: [frame.id, rect.id, text.id],
94
- rootNodeId: frame.id
95
- }))
96
-
97
- // CORRECT — when mutating existing nodes, return those IDs too
98
- const nodes = figma.currentPage.findAll(n => n.name === 'Card')
99
- for (const n of nodes) {
100
- n.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
101
- }
102
- figma.closePlugin(JSON.stringify({
103
- mutatedNodeIds: nodes.map(n => n.id),
104
- count: nodes.length
105
- }))
106
- ```
107
-
108
- ## Colors are 0–1 range
109
-
110
- ```js
111
- // WRONG — will throw validation error (ZeroToOne enforced)
112
- node.fills = [{ type: 'SOLID', color: { r: 255, g: 0, b: 0 } }]
113
-
114
- // CORRECT
115
- node.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
116
- ```
117
-
118
- ## Fills/strokes are immutable arrays
119
-
120
- ```js
121
- // WRONG — modifying in place does nothing
122
- node.fills[0].color = { r: 1, g: 0, b: 0 }
123
-
124
- // CORRECT — clone, modify, reassign
125
- const fills = JSON.parse(JSON.stringify(node.fills))
126
- fills[0].color = { r: 1, g: 0, b: 0 }
127
- node.fills = fills
128
- ```
129
-
130
- ## setBoundVariableForPaint returns a NEW paint
131
-
132
- ```js
133
- // WRONG — ignoring return value
134
- figma.variables.setBoundVariableForPaint(paint, "color", colorVar)
135
- node.fills = [paint] // paint is unchanged!
136
-
137
- // CORRECT — capture the returned new paint
138
- const boundPaint = figma.variables.setBoundVariableForPaint(paint, "color", colorVar)
139
- node.fills = [boundPaint]
140
- ```
141
-
142
- ## Variable collection starts with 1 mode
143
-
144
- ```js
145
- // A new collection already has one mode — rename it, don't try to add first
146
- const collection = figma.variables.createVariableCollection("Colors")
147
- // collection.modes = [{ modeId: "...", name: "Mode 1" }]
148
- collection.renameMode(collection.modes[0].modeId, "Light")
149
- const darkModeId = collection.addMode("Dark")
150
- ```
151
-
152
- ## combineAsVariants requires ComponentNodes
153
-
154
- ```js
155
- // WRONG — passing frames
156
- const f1 = figma.createFrame()
157
- figma.combineAsVariants([f1], figma.currentPage) // Error!
158
-
159
- // CORRECT — passing components
160
- const c1 = figma.createComponent()
161
- c1.name = "variant=primary, size=md"
162
- const c2 = figma.createComponent()
163
- c2.name = "variant=secondary, size=md"
164
- figma.combineAsVariants([c1, c2], figma.currentPage)
165
- ```
166
-
167
- ## Page switching: sync setter throws
168
-
169
- The sync setter `figma.currentPage = page` **throws an error** in `use_figma` runtimes (MCP, evals, assistant). Use `await figma.setCurrentPageAsync(page)` instead — it switches the page and loads its content.
170
-
171
- ```js
172
- // WRONG — throws "Setting figma.currentPage is not supported in this runtime"
173
- figma.currentPage = targetPage
174
-
175
- // CORRECT — async method switches and loads content
176
- await figma.setCurrentPageAsync(targetPage)
177
- ```
178
-
179
- ## `get_metadata` only sees one page — use `use_figma` to discover all pages
180
-
181
- A Figma file can have multiple pages (canvas nodes). `get_metadata` operates on a single node/page — it cannot scan the entire document. To discover all pages and their top-level contents, use `use_figma`:
182
-
183
- ```js
184
- // WRONG — calling get_metadata with the file root or expecting it to list all pages
185
- // get_metadata only returns the subtree of the node you pass it
186
-
187
- // CORRECT — use use_figma to list pages, then inspect each one
188
- const pages = figma.root.children.map(p => `${p.name} id=${p.id} children=${p.children.length}`);
189
- figma.closePlugin(pages.join('\n'));
190
- ```
191
-
192
- Icons, variables, and components may live on pages other than the first. Always enumerate all pages before concluding that the file has no existing assets.
193
-
194
- ## Never use figma.notify()
195
-
196
- ```js
197
- // WRONG — throws "not implemented" error
198
- figma.notify("Done!")
199
-
200
- // CORRECT — use closePlugin for messaging
201
- figma.closePlugin("Done!")
202
- ```
203
-
204
- ## Script must always terminate
205
-
206
- ```js
207
- // WRONG — no closePlugin call, script hangs
208
- (async () => {
209
- figma.createRectangle()
210
- })()
211
-
212
- // CORRECT — always close
213
- (async () => {
214
- try {
215
- figma.createRectangle()
216
- figma.closePlugin("created")
217
- } catch(e) {
218
- figma.closePluginWithFailure(e.toString())
219
- }
220
- })()
221
- ```
222
-
223
- ## setBoundVariable for paint fields only works on SOLID paints
224
-
225
- ```js
226
- // Only SOLID paint type supports color variable binding
227
- // Gradient paints, image paints, etc. will throw
228
- const solidPaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
229
- const bound = figma.variables.setBoundVariableForPaint(solidPaint, "color", colorVar)
230
- ```
231
-
232
- ## Explicit variable modes must be set per component
233
-
234
- ```js
235
- // WRONG — all variants render with the default (first) mode
236
- const colorCollection = figma.variables.createVariableCollection("Colors")
237
- // ... create variables and modes ...
238
- // Components all show the first mode's values by default!
239
-
240
- // CORRECT — set explicit mode on each component to get variant-specific values
241
- component.setExplicitVariableModeForCollection(colorCollection.id, targetModeId)
242
- ```
243
-
244
- ## `TextStyle.setBoundVariable` is not available in headless use_figma
245
-
246
- `setBoundVariable` exists on `TextStyle` in the typed API but is **not available** when running scripts through `use_figma` (MCP, headless assistant mode). Calling it will throw `"not a function"`.
247
-
248
- ```js
249
- // WRONG — throws "not a function" in use_figma / headless
250
- const ts = figma.createTextStyle()
251
- ts.setBoundVariable("fontSize", fontSizeVar)
252
-
253
- // CORRECT (headless) — set raw values; bind variables interactively in Figma later
254
- const ts = figma.createTextStyle()
255
- ts.fontSize = 24
256
- ```
257
-
258
- This only affects `TextStyle`. Variable binding on **nodes** (`node.setBoundVariable(...)`) and on **paint objects** (`figma.variables.setBoundVariableForPaint(...)`) still works in headless mode as expected.
259
-
260
- If live variable binding on text styles is required, create the styles with raw values via `use_figma`, then bind variables interactively through the Figma Styles panel or a full interactive plugin.
261
-
262
- ## `lineHeight` and `letterSpacing` must be objects, not bare numbers
263
-
264
- ```js
265
- // WRONG — throws or silently does nothing
266
- style.lineHeight = 1.5
267
- style.lineHeight = 24
268
- style.letterSpacing = 0
269
-
270
- // CORRECT
271
- style.lineHeight = { unit: "AUTO" } // auto/intrinsic
272
- style.lineHeight = { value: 24, unit: "PIXELS" } // fixed pixel height
273
- style.lineHeight = { value: 150, unit: "PERCENT" } // percentage of font size
274
-
275
- style.letterSpacing = { value: 0, unit: "PIXELS" } // no tracking
276
- style.letterSpacing = { value: -0.5, unit: "PIXELS" } // tight
277
- style.letterSpacing = { value: 5, unit: "PERCENT" } // percent-based
278
- ```
279
-
280
- This applies to both `TextStyle` and `TextNode` properties. The same rule applies inside `use_figma`, interactive plugins, and any other plugin API context.
281
-
282
- ## Font style names are file-dependent — probe before assuming
283
-
284
- Font style names vary per provider and per Figma file. `"SemiBold"` and `"Semi Bold"` are different strings. Loading a font with the wrong style string **throws silently or errors** — there is no canonical list.
285
-
286
- ```js
287
- // WRONG — guessing style names
288
- await figma.loadFontAsync({ family: "Inter", style: "SemiBold" }) // may throw
289
-
290
- // CORRECT — probe which style names are available
291
- const candidates = ["SemiBold", "Semi Bold", "Semibold"]
292
- for (const style of candidates) {
293
- try {
294
- await figma.loadFontAsync({ family: "Inter", style })
295
- // capture the one that works
296
- break
297
- } catch (_) {}
298
- }
299
- ```
300
-
301
- When building a type ramp script, always verify font styles against the target file before hardcoding them.
302
-
303
- ## combineAsVariants does NOT auto-layout in headless mode
304
-
305
- ```js
306
- // WRONG — all variants stack at position (0, 0), resulting in a tiny ComponentSet
307
- const components = [comp1, comp2, comp3]
308
- const cs = figma.combineAsVariants(components, figma.currentPage)
309
- // cs.width/height will be the size of a SINGLE variant!
310
-
311
- // CORRECT — manually layout children in a grid after combining
312
- const cs = figma.combineAsVariants(components, figma.currentPage)
313
- const colWidth = 120
314
- const rowHeight = 56
315
- cs.children.forEach((child, i) => {
316
- const col = i % numCols
317
- const row = Math.floor(i / numCols)
318
- child.x = col * colWidth
319
- child.y = row * rowHeight
320
- })
321
- // CRITICAL: resize from actual child bounds, not formula — formula errors leave variants outside the boundary
322
- let maxX = 0, maxY = 0
323
- for (const child of cs.children) {
324
- maxX = Math.max(maxX, child.x + child.width)
325
- maxY = Math.max(maxY, child.y + child.height)
326
- }
327
- cs.resizeWithoutConstraints(maxX + 40, maxY + 40)
328
- ```
329
-
330
- ## COLOR variable values use {r, g, b, a} (with alpha)
331
-
332
- ```js
333
- // Paint colors use {r, g, b} (no alpha — opacity is a separate paint property)
334
- node.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
335
-
336
- // But COLOR variable values use {r, g, b, a} — alpha maps to paint opacity
337
- const colorVar = figma.variables.createVariable("bg", collection, "COLOR")
338
- colorVar.setValueForMode(modeId, { r: 1, g: 0, b: 0, a: 1 }) // opaque red
339
- colorVar.setValueForMode(modeId, { r: 0, g: 0, b: 0, a: 0 }) // fully transparent
340
-
341
- // ⚠️ Don't confuse: {r, g, b} for paint colors vs {r, g, b, a} for variable values
342
- ```
343
-
344
- ## `layoutSizingVertical`/`layoutSizingHorizontal` = `'FILL'` requires auto-layout parent FIRST
345
-
346
- ```js
347
- // WRONG — setting FILL before the node is a child of an auto-layout frame
348
- const child = figma.createFrame()
349
- child.layoutSizingVertical = 'FILL' // ERROR: "FILL can only be set on children of auto-layout frames"
350
- parent.appendChild(child)
351
-
352
- // CORRECT — append to auto-layout parent FIRST, then set FILL
353
- const child = figma.createFrame()
354
- parent.appendChild(child) // parent must have layoutMode set
355
- child.layoutSizingVertical = 'FILL' // Works!
356
- ```
357
-
358
- ## HUG parents collapse FILL children
359
-
360
- A `HUG` parent cannot give `FILL` children meaningful size. If children have `layoutSizingHorizontal = "FILL"` but the parent is `"HUG"`, the children collapse to minimum size. The parent must be `"FILL"` or `"FIXED"` for FILL children to expand. This is a common cause of truncated text in select fields, inputs, and action rows.
361
-
362
- ```js
363
- // WRONG — parent hugs, so FILL children get zero extra space
364
- const parent = figma.createFrame()
365
- parent.layoutMode = 'HORIZONTAL'
366
- parent.layoutSizingHorizontal = 'HUG'
367
- const child = figma.createFrame()
368
- parent.appendChild(child)
369
- child.layoutSizingHorizontal = 'FILL' // collapses to min size!
370
-
371
- // CORRECT — parent must be FIXED or FILL for FILL children to expand
372
- const parent = figma.createFrame()
373
- parent.layoutMode = 'HORIZONTAL'
374
- parent.resize(400, 50)
375
- parent.layoutSizingHorizontal = 'FIXED' // or 'FILL' if inside another auto-layout
376
- const child = figma.createFrame()
377
- parent.appendChild(child)
378
- child.layoutSizingHorizontal = 'FILL' // expands to fill remaining 400px
379
- ```
380
-
381
- ## `layoutGrow` with a hugging parent causes content compression
382
-
383
- ```js
384
- // WRONG — layoutGrow on a child when parent has primaryAxisSizingMode='AUTO' (hug)
385
- // causes the child to SHRINK below its natural size instead of expanding
386
- const parent = figma.createComponent()
387
- parent.layoutMode = 'VERTICAL'
388
- parent.primaryAxisSizingMode = 'AUTO' // hug contents
389
- const content = figma.createFrame()
390
- content.layoutMode = 'VERTICAL'
391
- content.primaryAxisSizingMode = 'AUTO'
392
- parent.appendChild(content)
393
- content.layoutGrow = 1 // BUG: content compresses, children hidden!
394
-
395
- // CORRECT — only use layoutGrow when parent has FIXED sizing with extra space
396
- content.layoutGrow = 0 // let content take its natural size
397
- // OR: set parent to FIXED sizing first
398
- parent.primaryAxisSizingMode = 'FIXED'
399
- parent.resizeWithoutConstraints(300, 500)
400
- content.layoutGrow = 1 // NOW it correctly fills remaining space
401
- ```
402
-
403
- ## `resize()` resets `primaryAxisSizingMode` and `counterAxisSizingMode` to FIXED
404
-
405
- ```js
406
- // WRONG — resize() after setting sizing mode overwrites it back to FIXED
407
- const frame = figma.createComponent()
408
- frame.layoutMode = 'VERTICAL'
409
- frame.primaryAxisSizingMode = 'AUTO' // hug height
410
- frame.counterAxisSizingMode = 'FIXED'
411
- frame.resize(300, 10) // BUG: resets BOTH axes to 'FIXED'! Height stays at 10px forever.
412
-
413
- // CORRECT — call resize() FIRST, then set sizing modes
414
- const frame = figma.createComponent()
415
- frame.layoutMode = 'VERTICAL'
416
- frame.resize(300, 10) // set initial dimensions first
417
- frame.counterAxisSizingMode = 'FIXED' // keep width fixed at 300
418
- frame.primaryAxisSizingMode = 'AUTO' // NOW set height to hug — this sticks!
419
- // Or use the modern shorthand (equivalent):
420
- // frame.layoutSizingHorizontal = 'FIXED'
421
- // frame.layoutSizingVertical = 'HUG'
422
- ```
423
-
424
- ## Node positions don't auto-reset after reparenting
425
-
426
- ```js
427
- // WRONG — assuming positions reset when moving a node into a new parent
428
- const node = figma.createRectangle()
429
- node.x = 500; node.y = 500;
430
- figma.currentPage.appendChild(node)
431
- section.appendChild(node) // node still at (500, 500) relative to section!
432
-
433
- // CORRECT — explicitly set x/y after ANY reparenting operation
434
- section.appendChild(node)
435
- node.x = 80; node.y = 80; // reset to desired position within section
436
- ```
437
-
438
- ## Grid layout with mixed-width rows causes overlaps
439
-
440
- ```js
441
- // WRONG — using a single column offset for rows with different-width items
442
- // e.g. vertical cards (320px) and horizontal cards (500px) in a 2-row grid
443
- for (let i = 0; i < allCards.length; i++) {
444
- allCards[i].x = (i % 4) * 370 // 370 works for 320px cards but NOT 500px cards!
445
- }
446
-
447
- // CORRECT — compute each row's spacing independently based on actual child widths
448
- const gap = 50
449
- let x = 0
450
- for (const card of horizontalCards) {
451
- card.x = x
452
- x += card.width + gap // use actual width, not a fixed column size
453
- }
454
- ```
455
-
456
- ## Sections don't auto-resize to fit content
457
-
458
- ```js
459
- // WRONG — section stays at default size, content overflows
460
- const section = figma.createSection()
461
- section.name = "My Section"
462
- section.appendChild(someNode) // node may be outside section bounds
463
-
464
- // CORRECT — explicitly resize after adding content
465
- const section = figma.createSection()
466
- section.name = "My Section"
467
- section.appendChild(someNode)
468
- section.resizeWithoutConstraints(
469
- Math.max(someNode.width + 100, 800),
470
- Math.max(someNode.height + 100, 600)
471
- )
472
- ```
473
-
474
- ## `counterAxisAlignItems` does NOT support `'STRETCH'`
475
-
476
- ```js
477
- // WRONG — 'STRETCH' is not a valid enum value
478
- comp.counterAxisAlignItems = 'STRETCH'
479
- // Error: Invalid enum value. Expected 'MIN' | 'MAX' | 'CENTER' | 'BASELINE', received 'STRETCH'
480
-
481
- // CORRECT — use 'MIN' on the parent, then set children to FILL on the cross axis
482
- comp.counterAxisAlignItems = 'MIN'
483
- comp.appendChild(child)
484
- // For vertical layout, stretch width:
485
- child.layoutSizingHorizontal = 'FILL'
486
- // For horizontal layout, stretch height:
487
- child.layoutSizingVertical = 'FILL'
488
- ```
489
-
490
- ## Variable collection mode limits are plan-dependent
491
-
492
- ```js
493
- // Figma limits modes per collection based on the team/org plan:
494
- // Free: 1 mode only (no addMode)
495
- // Professional: up to 4 modes
496
- // Organization/Enterprise: up to 40+ modes
497
- //
498
- // WRONG — creating 20 modes on a Professional plan will fail silently or throw
499
- const coll = figma.variables.createVariableCollection("Variants")
500
- for (let i = 0; i < 20; i++) coll.addMode("mode" + i) // May fail!
501
-
502
- // CORRECT — if you need many modes, split across multiple collections
503
- // E.g., instead of 1 collection with 20 modes (variant×color):
504
- // Collection A: 4 modes (variant: plain/outlined/soft/solid)
505
- // Collection B: 5 modes (color: neutral/primary/danger/success/warning)
506
- // Then use setExplicitVariableModeForCollection for BOTH on each component
507
- ```
508
-
509
- ## Variables default to `ALL_SCOPES` — always set scopes explicitly
510
-
511
- ```js
512
- // WRONG — variable appears in every property picker (fills, text, strokes, spacing, etc.)
513
- const bgColor = figma.variables.createVariable("Background/Default", coll, "COLOR")
514
- // bgColor.scopes defaults to ["ALL_SCOPES"] — pollutes all dropdowns
515
-
516
- // CORRECT — restrict to relevant property pickers
517
- const bgColor = figma.variables.createVariable("Background/Default", coll, "COLOR")
518
- bgColor.scopes = ["FRAME_FILL", "SHAPE_FILL", "EFFECT_COLOR"] // fill pickers only
519
-
520
- const textColor = figma.variables.createVariable("Text/Default", coll, "COLOR")
521
- textColor.scopes = ["TEXT_FILL"] // text color picker only
522
-
523
- const borderColor = figma.variables.createVariable("Border/Default", coll, "COLOR")
524
- borderColor.scopes = ["STROKE_COLOR"] // stroke picker only
525
-
526
- const spacing = figma.variables.createVariable("Space/400", coll, "FLOAT")
527
- spacing.scopes = ["GAP"] // gap/spacing pickers only
528
-
529
- // Hide primitives that are only referenced via aliases
530
- const primitive = figma.variables.createVariable("Brand/500", coll, "COLOR")
531
- primitive.scopes = [] // hidden from all pickers
532
- ```
533
-
534
- ## Binding fills on nodes with empty fills
535
-
536
- ```js
537
- // WRONG — binding to a node with no fills does nothing
538
- const comp = figma.createComponent()
539
- comp.fills = [] // transparent
540
- // Can't bind a color variable to fills that don't exist
541
-
542
- // CORRECT — add a placeholder SOLID fill, then bind the variable
543
- const comp = figma.createComponent()
544
- const basePaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
545
- const boundPaint = figma.variables.setBoundVariableForPaint(basePaint, "color", colorVar)
546
- comp.fills = [boundPaint]
547
- // The variable's resolved value (which may be transparent) will control the actual color
548
- ```
549
-
550
- ## Mode names must be descriptive — never leave 'Mode 1'
551
-
552
- Every new `VariableCollection` starts with one mode named `'Mode 1'`. Always rename it immediately. For single-mode collections use `'Default'`; for multi-mode collections use names from the source (e.g. `'Light'`/`'Dark'`, `'Desktop'`/`'Tablet'`/`'Mobile'`).
553
-
554
- // WRONG — generic names give no semantic meaning
555
- const coll = figma.variables.createVariableCollection('Colors')
556
- // coll.modes[0].name === 'Mode 1' — left as-is
557
- const darkId = coll.addMode('Mode 2')
558
-
559
- // CORRECT — rename immediately to match the source
560
- const coll = figma.variables.createVariableCollection('Colors')
561
- coll.renameMode(coll.modes[0].modeId, 'Light') // was 'Mode 1'
562
- const darkId = coll.addMode('Dark')
563
-
564
- // For single-mode collections (primitives, spacing, etc.)
565
- const spacing = figma.variables.createVariableCollection('Spacing')
566
- spacing.renameMode(spacing.modes[0].modeId, 'Default') // was 'Mode 1'
567
-
568
- ## CSS variable names must not contain spaces
569
-
570
- When constructing a `var(--name)` string from a Figma variable name, replace BOTH slashes AND spaces with hyphens and convert to lowercase.
571
-
572
- // WRONG — only replacing slashes leaves spaces like 'var(--color-bg-brand secondary hover)'
573
- v.setVariableCodeSyntax('WEB', `var(--${figmaName.replace(/\//g, '-').toLowerCase()})`)
574
-
575
- // CORRECT — replace all whitespace and slashes in one pass
576
- v.setVariableCodeSyntax('WEB', `var(--${figmaName.replace(/[\s\/]+/g, '-').toLowerCase()})`)
577
-
578
- **Best practice**: Preserve the original CSS variable name from the source token file rather than deriving it from the Figma name.
579
-
580
- // Preferred — use the source CSS name directly
581
- v.setVariableCodeSyntax('WEB', `var(${token.cssVar})`) // e.g. '--color-bg-brand-secondary-hover'
582
-
583
- ## `detachInstance()` invalidates ancestor node IDs
584
-
585
- When `detachInstance()` is called on a nested instance inside a library component instance, the parent instance may also get implicitly detached (converted from INSTANCE to FRAME with a **new ID**). Any previously cached ID for the parent becomes invalid.
586
-
587
- ```js
588
- // WRONG — using cached parent ID after child detach
589
- const parentId = parentInstance.id;
590
- nestedChild.detachInstance();
591
- const parent = await figma.getNodeByIdAsync(parentId); // null! ID changed.
592
-
593
- // CORRECT — re-discover by traversal from a stable (non-instance) frame
594
- const stableFrame = await figma.getNodeByIdAsync(manualFrameId);
595
- nestedChild.detachInstance();
596
- const parent = stableFrame.findOne(n => n.name === "ParentName");
597
- ```
598
-
599
- If detaching multiple nested instances across siblings, do it in a **single** `use_figma` call — discover all targets by traversal before any detachment mutates the tree.
1
+ # Gotchas & Common Mistakes
2
+
3
+ > Part of the [use_figma skill](../SKILL.md). Every known pitfall with WRONG/CORRECT code examples.
4
+
5
+ ## Contents
6
+
7
+ - Component properties and variant creation pitfalls
8
+ - Paint, color, and variable binding pitfalls
9
+ - Page context and plugin lifecycle pitfalls
10
+ - Auto Layout and sizing order pitfalls (including HUG/FILL interactions)
11
+ - Variant layout and geometry pitfalls
12
+ - Variable scopes and mode pitfalls
13
+ - Node cleanup and empty-fill pitfalls
14
+ - detachInstance() and node ID invalidation
15
+
16
+
17
+ ## New nodes default to (0,0) and overlap existing content
18
+
19
+ Every `figma.create*()` call places the node at position (0,0). If you append multiple nodes directly to the page, they all stack on top of each other and on top of any existing content.
20
+
21
+ **This only matters for nodes appended directly to the page** (i.e., top-level nodes). Nodes appended as children of other frames, components, or auto-layout containers are positioned by their parent — don't scan for overlaps when nesting nodes.
22
+
23
+ ```js
24
+ // WRONG — top-level node lands at (0,0), overlapping existing page content
25
+ const frame = figma.createFrame()
26
+ frame.name = "My New Frame"
27
+ frame.resize(400, 300)
28
+ figma.currentPage.appendChild(frame)
29
+
30
+ // CORRECT — find existing content bounds and place the new top-level node to the right
31
+ const page = figma.currentPage
32
+ let maxX = 0
33
+ for (const child of page.children) {
34
+ const right = child.x + child.width
35
+ if (right > maxX) maxX = right
36
+ }
37
+ const frame = figma.createFrame()
38
+ frame.name = "My New Frame"
39
+ frame.resize(400, 300)
40
+ figma.currentPage.appendChild(frame)
41
+ frame.x = maxX + 100 // 100px gap from rightmost existing content
42
+ frame.y = 0
43
+
44
+ // NOT NEEDED — child nodes inside a parent don't need overlap scanning
45
+ const card = figma.createFrame()
46
+ card.layoutMode = 'VERTICAL'
47
+ const label = figma.createText()
48
+ card.appendChild(label) // positioned by auto-layout, no x/y needed
49
+ ```
50
+
51
+ ## `addComponentProperty` returns a string key, not an object — never hardcode or guess it
52
+
53
+ Figma generates the property key dynamically (e.g. `"label#4:0"`). The suffix is unpredictable. Always capture and use the return value directly.
54
+
55
+ ```js
56
+ // WRONG — guessing / hardcoding the key
57
+ comp.addComponentProperty('label', 'TEXT', 'Button')
58
+ labelNode.componentPropertyReferences = { characters: 'label#0:1' } // Error: key not found
59
+
60
+ // WRONG — treating the return value as an object
61
+ const result = comp.addComponentProperty('Label', 'TEXT', 'Button')
62
+ const propKey = Object.keys(result)[0] // BUG: returns '0' (first char index of string!)
63
+ labelNode.componentPropertyReferences = { characters: propKey } // Error: property '0' not found
64
+
65
+ // CORRECT — the return value IS the key string, use it directly
66
+ const propKey = comp.addComponentProperty('Label', 'TEXT', 'Button')
67
+ // propKey === "label#4:0" (exact value varies; never assume it)
68
+ labelNode.componentPropertyReferences = { characters: propKey }
69
+ ```
70
+
71
+ The same applies to `COMPONENT_SET` nodes — `addComponentProperty` always returns the property key as a string.
72
+
73
+ ## MUST return ALL created/mutated node IDs
74
+
75
+ Every script that creates or mutates nodes on the canvas must track and return all affected node IDs in the `figma.closePlugin()` response. Without these IDs, subsequent calls cannot reference, validate, or clean up those nodes.
76
+
77
+ ```js
78
+ // WRONG — only returns the parent frame ID, loses track of children
79
+ const frame = figma.createFrame()
80
+ const rect = figma.createRectangle()
81
+ const text = figma.createText()
82
+ frame.appendChild(rect)
83
+ frame.appendChild(text)
84
+ figma.closePlugin(JSON.stringify({ nodeId: frame.id }))
85
+
86
+ // CORRECT — returns all created node IDs in a structured response
87
+ const frame = figma.createFrame()
88
+ const rect = figma.createRectangle()
89
+ const text = figma.createText()
90
+ frame.appendChild(rect)
91
+ frame.appendChild(text)
92
+ figma.closePlugin(JSON.stringify({
93
+ createdNodeIds: [frame.id, rect.id, text.id],
94
+ rootNodeId: frame.id
95
+ }))
96
+
97
+ // CORRECT — when mutating existing nodes, return those IDs too
98
+ const nodes = figma.currentPage.findAll(n => n.name === 'Card')
99
+ for (const n of nodes) {
100
+ n.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
101
+ }
102
+ figma.closePlugin(JSON.stringify({
103
+ mutatedNodeIds: nodes.map(n => n.id),
104
+ count: nodes.length
105
+ }))
106
+ ```
107
+
108
+ ## Colors are 0–1 range
109
+
110
+ ```js
111
+ // WRONG — will throw validation error (ZeroToOne enforced)
112
+ node.fills = [{ type: 'SOLID', color: { r: 255, g: 0, b: 0 } }]
113
+
114
+ // CORRECT
115
+ node.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
116
+ ```
117
+
118
+ ## Fills/strokes are immutable arrays
119
+
120
+ ```js
121
+ // WRONG — modifying in place does nothing
122
+ node.fills[0].color = { r: 1, g: 0, b: 0 }
123
+
124
+ // CORRECT — clone, modify, reassign
125
+ const fills = JSON.parse(JSON.stringify(node.fills))
126
+ fills[0].color = { r: 1, g: 0, b: 0 }
127
+ node.fills = fills
128
+ ```
129
+
130
+ ## setBoundVariableForPaint returns a NEW paint
131
+
132
+ ```js
133
+ // WRONG — ignoring return value
134
+ figma.variables.setBoundVariableForPaint(paint, "color", colorVar)
135
+ node.fills = [paint] // paint is unchanged!
136
+
137
+ // CORRECT — capture the returned new paint
138
+ const boundPaint = figma.variables.setBoundVariableForPaint(paint, "color", colorVar)
139
+ node.fills = [boundPaint]
140
+ ```
141
+
142
+ ## Variable collection starts with 1 mode
143
+
144
+ ```js
145
+ // A new collection already has one mode — rename it, don't try to add first
146
+ const collection = figma.variables.createVariableCollection("Colors")
147
+ // collection.modes = [{ modeId: "...", name: "Mode 1" }]
148
+ collection.renameMode(collection.modes[0].modeId, "Light")
149
+ const darkModeId = collection.addMode("Dark")
150
+ ```
151
+
152
+ ## combineAsVariants requires ComponentNodes
153
+
154
+ ```js
155
+ // WRONG — passing frames
156
+ const f1 = figma.createFrame()
157
+ figma.combineAsVariants([f1], figma.currentPage) // Error!
158
+
159
+ // CORRECT — passing components
160
+ const c1 = figma.createComponent()
161
+ c1.name = "variant=primary, size=md"
162
+ const c2 = figma.createComponent()
163
+ c2.name = "variant=secondary, size=md"
164
+ figma.combineAsVariants([c1, c2], figma.currentPage)
165
+ ```
166
+
167
+ ## Page switching: sync setter throws
168
+
169
+ The sync setter `figma.currentPage = page` **throws an error** in `use_figma` runtimes (MCP, evals, assistant). Use `await figma.setCurrentPageAsync(page)` instead — it switches the page and loads its content.
170
+
171
+ ```js
172
+ // WRONG — throws "Setting figma.currentPage is not supported in this runtime"
173
+ figma.currentPage = targetPage
174
+
175
+ // CORRECT — async method switches and loads content
176
+ await figma.setCurrentPageAsync(targetPage)
177
+ ```
178
+
179
+ ## `get_metadata` only sees one page — use `use_figma` to discover all pages
180
+
181
+ A Figma file can have multiple pages (canvas nodes). `get_metadata` operates on a single node/page — it cannot scan the entire document. To discover all pages and their top-level contents, use `use_figma`:
182
+
183
+ ```js
184
+ // WRONG — calling get_metadata with the file root or expecting it to list all pages
185
+ // get_metadata only returns the subtree of the node you pass it
186
+
187
+ // CORRECT — use use_figma to list pages, then inspect each one
188
+ const pages = figma.root.children.map(p => `${p.name} id=${p.id} children=${p.children.length}`);
189
+ figma.closePlugin(pages.join('\n'));
190
+ ```
191
+
192
+ Icons, variables, and components may live on pages other than the first. Always enumerate all pages before concluding that the file has no existing assets.
193
+
194
+ ## Never use figma.notify()
195
+
196
+ ```js
197
+ // WRONG — throws "not implemented" error
198
+ figma.notify("Done!")
199
+
200
+ // CORRECT — use closePlugin for messaging
201
+ figma.closePlugin("Done!")
202
+ ```
203
+
204
+ ## Script must always terminate
205
+
206
+ ```js
207
+ // WRONG — no closePlugin call, script hangs
208
+ (async () => {
209
+ figma.createRectangle()
210
+ })()
211
+
212
+ // CORRECT — always close
213
+ (async () => {
214
+ try {
215
+ figma.createRectangle()
216
+ figma.closePlugin("created")
217
+ } catch(e) {
218
+ figma.closePluginWithFailure(e.toString())
219
+ }
220
+ })()
221
+ ```
222
+
223
+ ## setBoundVariable for paint fields only works on SOLID paints
224
+
225
+ ```js
226
+ // Only SOLID paint type supports color variable binding
227
+ // Gradient paints, image paints, etc. will throw
228
+ const solidPaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
229
+ const bound = figma.variables.setBoundVariableForPaint(solidPaint, "color", colorVar)
230
+ ```
231
+
232
+ ## Explicit variable modes must be set per component
233
+
234
+ ```js
235
+ // WRONG — all variants render with the default (first) mode
236
+ const colorCollection = figma.variables.createVariableCollection("Colors")
237
+ // ... create variables and modes ...
238
+ // Components all show the first mode's values by default!
239
+
240
+ // CORRECT — set explicit mode on each component to get variant-specific values
241
+ component.setExplicitVariableModeForCollection(colorCollection.id, targetModeId)
242
+ ```
243
+
244
+ ## `TextStyle.setBoundVariable` is not available in headless use_figma
245
+
246
+ `setBoundVariable` exists on `TextStyle` in the typed API but is **not available** when running scripts through `use_figma` (MCP, headless assistant mode). Calling it will throw `"not a function"`.
247
+
248
+ ```js
249
+ // WRONG — throws "not a function" in use_figma / headless
250
+ const ts = figma.createTextStyle()
251
+ ts.setBoundVariable("fontSize", fontSizeVar)
252
+
253
+ // CORRECT (headless) — set raw values; bind variables interactively in Figma later
254
+ const ts = figma.createTextStyle()
255
+ ts.fontSize = 24
256
+ ```
257
+
258
+ This only affects `TextStyle`. Variable binding on **nodes** (`node.setBoundVariable(...)`) and on **paint objects** (`figma.variables.setBoundVariableForPaint(...)`) still works in headless mode as expected.
259
+
260
+ If live variable binding on text styles is required, create the styles with raw values via `use_figma`, then bind variables interactively through the Figma Styles panel or a full interactive plugin.
261
+
262
+ ## `lineHeight` and `letterSpacing` must be objects, not bare numbers
263
+
264
+ ```js
265
+ // WRONG — throws or silently does nothing
266
+ style.lineHeight = 1.5
267
+ style.lineHeight = 24
268
+ style.letterSpacing = 0
269
+
270
+ // CORRECT
271
+ style.lineHeight = { unit: "AUTO" } // auto/intrinsic
272
+ style.lineHeight = { value: 24, unit: "PIXELS" } // fixed pixel height
273
+ style.lineHeight = { value: 150, unit: "PERCENT" } // percentage of font size
274
+
275
+ style.letterSpacing = { value: 0, unit: "PIXELS" } // no tracking
276
+ style.letterSpacing = { value: -0.5, unit: "PIXELS" } // tight
277
+ style.letterSpacing = { value: 5, unit: "PERCENT" } // percent-based
278
+ ```
279
+
280
+ This applies to both `TextStyle` and `TextNode` properties. The same rule applies inside `use_figma`, interactive plugins, and any other plugin API context.
281
+
282
+ ## Font style names are file-dependent — probe before assuming
283
+
284
+ Font style names vary per provider and per Figma file. `"SemiBold"` and `"Semi Bold"` are different strings. Loading a font with the wrong style string **throws silently or errors** — there is no canonical list.
285
+
286
+ ```js
287
+ // WRONG — guessing style names
288
+ await figma.loadFontAsync({ family: "Inter", style: "SemiBold" }) // may throw
289
+
290
+ // CORRECT — probe which style names are available
291
+ const candidates = ["SemiBold", "Semi Bold", "Semibold"]
292
+ for (const style of candidates) {
293
+ try {
294
+ await figma.loadFontAsync({ family: "Inter", style })
295
+ // capture the one that works
296
+ break
297
+ } catch (_) {}
298
+ }
299
+ ```
300
+
301
+ When building a type ramp script, always verify font styles against the target file before hardcoding them.
302
+
303
+ ## combineAsVariants does NOT auto-layout in headless mode
304
+
305
+ ```js
306
+ // WRONG — all variants stack at position (0, 0), resulting in a tiny ComponentSet
307
+ const components = [comp1, comp2, comp3]
308
+ const cs = figma.combineAsVariants(components, figma.currentPage)
309
+ // cs.width/height will be the size of a SINGLE variant!
310
+
311
+ // CORRECT — manually layout children in a grid after combining
312
+ const cs = figma.combineAsVariants(components, figma.currentPage)
313
+ const colWidth = 120
314
+ const rowHeight = 56
315
+ cs.children.forEach((child, i) => {
316
+ const col = i % numCols
317
+ const row = Math.floor(i / numCols)
318
+ child.x = col * colWidth
319
+ child.y = row * rowHeight
320
+ })
321
+ // CRITICAL: resize from actual child bounds, not formula — formula errors leave variants outside the boundary
322
+ let maxX = 0, maxY = 0
323
+ for (const child of cs.children) {
324
+ maxX = Math.max(maxX, child.x + child.width)
325
+ maxY = Math.max(maxY, child.y + child.height)
326
+ }
327
+ cs.resizeWithoutConstraints(maxX + 40, maxY + 40)
328
+ ```
329
+
330
+ ## COLOR variable values use {r, g, b, a} (with alpha)
331
+
332
+ ```js
333
+ // Paint colors use {r, g, b} (no alpha — opacity is a separate paint property)
334
+ node.fills = [{ type: 'SOLID', color: { r: 1, g: 0, b: 0 } }]
335
+
336
+ // But COLOR variable values use {r, g, b, a} — alpha maps to paint opacity
337
+ const colorVar = figma.variables.createVariable("bg", collection, "COLOR")
338
+ colorVar.setValueForMode(modeId, { r: 1, g: 0, b: 0, a: 1 }) // opaque red
339
+ colorVar.setValueForMode(modeId, { r: 0, g: 0, b: 0, a: 0 }) // fully transparent
340
+
341
+ // ⚠️ Don't confuse: {r, g, b} for paint colors vs {r, g, b, a} for variable values
342
+ ```
343
+
344
+ ## `layoutSizingVertical`/`layoutSizingHorizontal` = `'FILL'` requires auto-layout parent FIRST
345
+
346
+ ```js
347
+ // WRONG — setting FILL before the node is a child of an auto-layout frame
348
+ const child = figma.createFrame()
349
+ child.layoutSizingVertical = 'FILL' // ERROR: "FILL can only be set on children of auto-layout frames"
350
+ parent.appendChild(child)
351
+
352
+ // CORRECT — append to auto-layout parent FIRST, then set FILL
353
+ const child = figma.createFrame()
354
+ parent.appendChild(child) // parent must have layoutMode set
355
+ child.layoutSizingVertical = 'FILL' // Works!
356
+ ```
357
+
358
+ ## HUG parents collapse FILL children
359
+
360
+ A `HUG` parent cannot give `FILL` children meaningful size. If children have `layoutSizingHorizontal = "FILL"` but the parent is `"HUG"`, the children collapse to minimum size. The parent must be `"FILL"` or `"FIXED"` for FILL children to expand. This is a common cause of truncated text in select fields, inputs, and action rows.
361
+
362
+ ```js
363
+ // WRONG — parent hugs, so FILL children get zero extra space
364
+ const parent = figma.createFrame()
365
+ parent.layoutMode = 'HORIZONTAL'
366
+ parent.layoutSizingHorizontal = 'HUG'
367
+ const child = figma.createFrame()
368
+ parent.appendChild(child)
369
+ child.layoutSizingHorizontal = 'FILL' // collapses to min size!
370
+
371
+ // CORRECT — parent must be FIXED or FILL for FILL children to expand
372
+ const parent = figma.createFrame()
373
+ parent.layoutMode = 'HORIZONTAL'
374
+ parent.resize(400, 50)
375
+ parent.layoutSizingHorizontal = 'FIXED' // or 'FILL' if inside another auto-layout
376
+ const child = figma.createFrame()
377
+ parent.appendChild(child)
378
+ child.layoutSizingHorizontal = 'FILL' // expands to fill remaining 400px
379
+ ```
380
+
381
+ ## `layoutGrow` with a hugging parent causes content compression
382
+
383
+ ```js
384
+ // WRONG — layoutGrow on a child when parent has primaryAxisSizingMode='AUTO' (hug)
385
+ // causes the child to SHRINK below its natural size instead of expanding
386
+ const parent = figma.createComponent()
387
+ parent.layoutMode = 'VERTICAL'
388
+ parent.primaryAxisSizingMode = 'AUTO' // hug contents
389
+ const content = figma.createFrame()
390
+ content.layoutMode = 'VERTICAL'
391
+ content.primaryAxisSizingMode = 'AUTO'
392
+ parent.appendChild(content)
393
+ content.layoutGrow = 1 // BUG: content compresses, children hidden!
394
+
395
+ // CORRECT — only use layoutGrow when parent has FIXED sizing with extra space
396
+ content.layoutGrow = 0 // let content take its natural size
397
+ // OR: set parent to FIXED sizing first
398
+ parent.primaryAxisSizingMode = 'FIXED'
399
+ parent.resizeWithoutConstraints(300, 500)
400
+ content.layoutGrow = 1 // NOW it correctly fills remaining space
401
+ ```
402
+
403
+ ## `resize()` resets `primaryAxisSizingMode` and `counterAxisSizingMode` to FIXED
404
+
405
+ ```js
406
+ // WRONG — resize() after setting sizing mode overwrites it back to FIXED
407
+ const frame = figma.createComponent()
408
+ frame.layoutMode = 'VERTICAL'
409
+ frame.primaryAxisSizingMode = 'AUTO' // hug height
410
+ frame.counterAxisSizingMode = 'FIXED'
411
+ frame.resize(300, 10) // BUG: resets BOTH axes to 'FIXED'! Height stays at 10px forever.
412
+
413
+ // CORRECT — call resize() FIRST, then set sizing modes
414
+ const frame = figma.createComponent()
415
+ frame.layoutMode = 'VERTICAL'
416
+ frame.resize(300, 10) // set initial dimensions first
417
+ frame.counterAxisSizingMode = 'FIXED' // keep width fixed at 300
418
+ frame.primaryAxisSizingMode = 'AUTO' // NOW set height to hug — this sticks!
419
+ // Or use the modern shorthand (equivalent):
420
+ // frame.layoutSizingHorizontal = 'FIXED'
421
+ // frame.layoutSizingVertical = 'HUG'
422
+ ```
423
+
424
+ ## Node positions don't auto-reset after reparenting
425
+
426
+ ```js
427
+ // WRONG — assuming positions reset when moving a node into a new parent
428
+ const node = figma.createRectangle()
429
+ node.x = 500; node.y = 500;
430
+ figma.currentPage.appendChild(node)
431
+ section.appendChild(node) // node still at (500, 500) relative to section!
432
+
433
+ // CORRECT — explicitly set x/y after ANY reparenting operation
434
+ section.appendChild(node)
435
+ node.x = 80; node.y = 80; // reset to desired position within section
436
+ ```
437
+
438
+ ## Grid layout with mixed-width rows causes overlaps
439
+
440
+ ```js
441
+ // WRONG — using a single column offset for rows with different-width items
442
+ // e.g. vertical cards (320px) and horizontal cards (500px) in a 2-row grid
443
+ for (let i = 0; i < allCards.length; i++) {
444
+ allCards[i].x = (i % 4) * 370 // 370 works for 320px cards but NOT 500px cards!
445
+ }
446
+
447
+ // CORRECT — compute each row's spacing independently based on actual child widths
448
+ const gap = 50
449
+ let x = 0
450
+ for (const card of horizontalCards) {
451
+ card.x = x
452
+ x += card.width + gap // use actual width, not a fixed column size
453
+ }
454
+ ```
455
+
456
+ ## Sections don't auto-resize to fit content
457
+
458
+ ```js
459
+ // WRONG — section stays at default size, content overflows
460
+ const section = figma.createSection()
461
+ section.name = "My Section"
462
+ section.appendChild(someNode) // node may be outside section bounds
463
+
464
+ // CORRECT — explicitly resize after adding content
465
+ const section = figma.createSection()
466
+ section.name = "My Section"
467
+ section.appendChild(someNode)
468
+ section.resizeWithoutConstraints(
469
+ Math.max(someNode.width + 100, 800),
470
+ Math.max(someNode.height + 100, 600)
471
+ )
472
+ ```
473
+
474
+ ## `counterAxisAlignItems` does NOT support `'STRETCH'`
475
+
476
+ ```js
477
+ // WRONG — 'STRETCH' is not a valid enum value
478
+ comp.counterAxisAlignItems = 'STRETCH'
479
+ // Error: Invalid enum value. Expected 'MIN' | 'MAX' | 'CENTER' | 'BASELINE', received 'STRETCH'
480
+
481
+ // CORRECT — use 'MIN' on the parent, then set children to FILL on the cross axis
482
+ comp.counterAxisAlignItems = 'MIN'
483
+ comp.appendChild(child)
484
+ // For vertical layout, stretch width:
485
+ child.layoutSizingHorizontal = 'FILL'
486
+ // For horizontal layout, stretch height:
487
+ child.layoutSizingVertical = 'FILL'
488
+ ```
489
+
490
+ ## Variable collection mode limits are plan-dependent
491
+
492
+ ```js
493
+ // Figma limits modes per collection based on the team/org plan:
494
+ // Free: 1 mode only (no addMode)
495
+ // Professional: up to 4 modes
496
+ // Organization/Enterprise: up to 40+ modes
497
+ //
498
+ // WRONG — creating 20 modes on a Professional plan will fail silently or throw
499
+ const coll = figma.variables.createVariableCollection("Variants")
500
+ for (let i = 0; i < 20; i++) coll.addMode("mode" + i) // May fail!
501
+
502
+ // CORRECT — if you need many modes, split across multiple collections
503
+ // E.g., instead of 1 collection with 20 modes (variant×color):
504
+ // Collection A: 4 modes (variant: plain/outlined/soft/solid)
505
+ // Collection B: 5 modes (color: neutral/primary/danger/success/warning)
506
+ // Then use setExplicitVariableModeForCollection for BOTH on each component
507
+ ```
508
+
509
+ ## Variables default to `ALL_SCOPES` — always set scopes explicitly
510
+
511
+ ```js
512
+ // WRONG — variable appears in every property picker (fills, text, strokes, spacing, etc.)
513
+ const bgColor = figma.variables.createVariable("Background/Default", coll, "COLOR")
514
+ // bgColor.scopes defaults to ["ALL_SCOPES"] — pollutes all dropdowns
515
+
516
+ // CORRECT — restrict to relevant property pickers
517
+ const bgColor = figma.variables.createVariable("Background/Default", coll, "COLOR")
518
+ bgColor.scopes = ["FRAME_FILL", "SHAPE_FILL", "EFFECT_COLOR"] // fill pickers only
519
+
520
+ const textColor = figma.variables.createVariable("Text/Default", coll, "COLOR")
521
+ textColor.scopes = ["TEXT_FILL"] // text color picker only
522
+
523
+ const borderColor = figma.variables.createVariable("Border/Default", coll, "COLOR")
524
+ borderColor.scopes = ["STROKE_COLOR"] // stroke picker only
525
+
526
+ const spacing = figma.variables.createVariable("Space/400", coll, "FLOAT")
527
+ spacing.scopes = ["GAP"] // gap/spacing pickers only
528
+
529
+ // Hide primitives that are only referenced via aliases
530
+ const primitive = figma.variables.createVariable("Brand/500", coll, "COLOR")
531
+ primitive.scopes = [] // hidden from all pickers
532
+ ```
533
+
534
+ ## Binding fills on nodes with empty fills
535
+
536
+ ```js
537
+ // WRONG — binding to a node with no fills does nothing
538
+ const comp = figma.createComponent()
539
+ comp.fills = [] // transparent
540
+ // Can't bind a color variable to fills that don't exist
541
+
542
+ // CORRECT — add a placeholder SOLID fill, then bind the variable
543
+ const comp = figma.createComponent()
544
+ const basePaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
545
+ const boundPaint = figma.variables.setBoundVariableForPaint(basePaint, "color", colorVar)
546
+ comp.fills = [boundPaint]
547
+ // The variable's resolved value (which may be transparent) will control the actual color
548
+ ```
549
+
550
+ ## Mode names must be descriptive — never leave 'Mode 1'
551
+
552
+ Every new `VariableCollection` starts with one mode named `'Mode 1'`. Always rename it immediately. For single-mode collections use `'Default'`; for multi-mode collections use names from the source (e.g. `'Light'`/`'Dark'`, `'Desktop'`/`'Tablet'`/`'Mobile'`).
553
+
554
+ // WRONG — generic names give no semantic meaning
555
+ const coll = figma.variables.createVariableCollection('Colors')
556
+ // coll.modes[0].name === 'Mode 1' — left as-is
557
+ const darkId = coll.addMode('Mode 2')
558
+
559
+ // CORRECT — rename immediately to match the source
560
+ const coll = figma.variables.createVariableCollection('Colors')
561
+ coll.renameMode(coll.modes[0].modeId, 'Light') // was 'Mode 1'
562
+ const darkId = coll.addMode('Dark')
563
+
564
+ // For single-mode collections (primitives, spacing, etc.)
565
+ const spacing = figma.variables.createVariableCollection('Spacing')
566
+ spacing.renameMode(spacing.modes[0].modeId, 'Default') // was 'Mode 1'
567
+
568
+ ## CSS variable names must not contain spaces
569
+
570
+ When constructing a `var(--name)` string from a Figma variable name, replace BOTH slashes AND spaces with hyphens and convert to lowercase.
571
+
572
+ // WRONG — only replacing slashes leaves spaces like 'var(--color-bg-brand secondary hover)'
573
+ v.setVariableCodeSyntax('WEB', `var(--${figmaName.replace(/\//g, '-').toLowerCase()})`)
574
+
575
+ // CORRECT — replace all whitespace and slashes in one pass
576
+ v.setVariableCodeSyntax('WEB', `var(--${figmaName.replace(/[\s\/]+/g, '-').toLowerCase()})`)
577
+
578
+ **Best practice**: Preserve the original CSS variable name from the source token file rather than deriving it from the Figma name.
579
+
580
+ // Preferred — use the source CSS name directly
581
+ v.setVariableCodeSyntax('WEB', `var(${token.cssVar})`) // e.g. '--color-bg-brand-secondary-hover'
582
+
583
+ ## `detachInstance()` invalidates ancestor node IDs
584
+
585
+ When `detachInstance()` is called on a nested instance inside a library component instance, the parent instance may also get implicitly detached (converted from INSTANCE to FRAME with a **new ID**). Any previously cached ID for the parent becomes invalid.
586
+
587
+ ```js
588
+ // WRONG — using cached parent ID after child detach
589
+ const parentId = parentInstance.id;
590
+ nestedChild.detachInstance();
591
+ const parent = await figma.getNodeByIdAsync(parentId); // null! ID changed.
592
+
593
+ // CORRECT — re-discover by traversal from a stable (non-instance) frame
594
+ const stableFrame = await figma.getNodeByIdAsync(manualFrameId);
595
+ nestedChild.detachInstance();
596
+ const parent = stableFrame.findOne(n => n.name === "ParentName");
597
+ ```
598
+
599
+ If detaching multiple nested instances across siblings, do it in a **single** `use_figma` call — discover all targets by traversal before any detachment mutates the tree.