@fprad0/skill-master-mcp 0.0.12 → 1.0.1
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.
- package/CHANGELOG.md +100 -88
- package/README.md +472 -472
- package/VERSION.md +9 -9
- package/bin/lib/bootstrap-global-core.mjs +34 -0
- package/bin/lib/client-config.mjs +287 -285
- package/bin/lib/doctor-core.mjs +202 -0
- package/bin/lib/menu-core.mjs +1792 -1514
- package/bin/lib/operation-result.mjs +59 -0
- package/bin/lib/register-clients-core.mjs +247 -0
- package/bin/lib/skill-installation.mjs +215 -215
- package/bin/lib/update-cli-core.mjs +117 -0
- package/bin/skill-master-activation.mjs +165 -163
- package/bin/skill-master-bootstrap-global.mjs +61 -49
- package/bin/skill-master-configure-private-registry.mjs +3 -3
- package/bin/skill-master-doctor.mjs +239 -228
- package/bin/skill-master-eval-activation.mjs +32 -32
- package/bin/skill-master-install-global-skills.mjs +59 -59
- package/bin/skill-master-install-project-skills.mjs +97 -97
- package/bin/skill-master-menu.mjs +489 -378
- package/bin/skill-master-register-clients.mjs +232 -153
- package/bin/skill-master-success-skills.mjs +357 -307
- package/bin/skill-master-update.mjs +121 -72
- package/bin/skill-master.mjs +3 -3
- package/dist/activation.d.ts.map +1 -1
- package/dist/activation.js +12 -0
- package/dist/activation.js.map +1 -1
- package/dist/prompt-router.d.ts.map +1 -1
- package/dist/prompt-router.js +19 -0
- package/dist/prompt-router.js.map +1 -1
- package/dist/recommender.d.ts.map +1 -1
- package/dist/recommender.js +4 -1
- package/dist/recommender.js.map +1 -1
- package/docs/architecture/APRENDIZADO_DE_IMPLEMENTACOES_BEM_SUCEDIDAS.md +125 -125
- package/docs/architecture/ARQUITETURA_AUTO_UPDATE.md +9 -9
- package/docs/architecture/PLANO_MASTER_ACIONAMENTO_AUTOMATICO_E_APRENDIZADO.md +341 -341
- package/docs/architecture/REDE_SEGURA_DE_SKILLS.md +148 -148
- package/docs/operations/GUIA_MULTI_COMPUTADOR.md +262 -262
- package/docs/operations/GUIA_NPM_PRIVADO.md +294 -294
- package/docs/operations/GUIA_NPM_PUBLICO.md +147 -147
- package/docs/operations/MENU_VISUAL_EVIDENCE_2026-06-28.md +66 -66
- package/docs/operations/assets/menu-frame-compact.html +36 -33
- package/docs/operations/assets/menu-frame-dna-hero.html +87 -0
- package/docs/operations/assets/menu-frame-fine-helix.html +89 -0
- package/docs/operations/assets/menu-frame-large.html +44 -41
- package/docs/operations/assets/menu-frame-running.html +41 -38
- package/docs/operations/assets/menu-frame-score-10-contact-sheet.html +184 -0
- package/docs/operations/cross-platform-auth-transfer/ANALISE_COMPATIBILIDADE_MCP_2026-06-28.md +140 -140
- package/docs/operations/cross-platform-auth-transfer/README_TRANSFERENCIA.md +85 -85
- package/docs/operations/reborn-menu-cyberpunk-transfer/ANALISE_MENU_REBORN_CYBERPUNK_2026-06-28.md +174 -174
- package/docs/operations/reborn-menu-cyberpunk-transfer/HANDOFF_IMPLEMENTACAO_REBORN_CYBERPUNK_2026-06-28.md +119 -119
- package/docs/operations/reborn-menu-cyberpunk-transfer/ORDEM_DE_EXECUCAO_MENU_REBORN_CYBERPUNK.md +134 -134
- package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA.md +84 -84
- package/docs/operations/reborn-menu-cyberpunk-transfer/README_TRANSFERENCIA_REBORN_PACKAGE.md +56 -56
- package/docs/operations/token-economy-transfer/ANALISE_AVANCADA_ECONOMIA_TOKENS_2026-06-30.md +141 -0
- package/docs/operations/token-economy-transfer/PLANO_DEV_SENIOR_MASTER_TOKEN_ECONOMY_2026-06-30.md +171 -0
- package/docs/operations/token-economy-transfer/README_TRANSFERENCIA_TOKEN_ECONOMY.md +31 -0
- package/docs/planning/MENU_RUNTIME_CORRECTION_PLAN_2026-06-30.md +551 -0
- package/docs/planning/V0_0_9_APROVACAO_CRITICA_MENSAGENS_DE_VENDA.md +85 -85
- package/docs/planning/V0_0_9_FONTES_E_CRITERIOS_DE_AUTORIDADE.md +139 -139
- package/docs/planning/V0_0_9_MATRIZ_SKILLS_MULTIDISCIPLINARES.md +105 -105
- package/docs/planning/V0_0_9_POLITICA_MORAL_CATOLICA_PARA_IA.md +181 -181
- package/docs/planning/V0_0_9_PROMPTS_EXECUCAO.md +59 -59
- package/docs/planning/V0_0_9_ROADMAP_DISCERNIMENTO_E_CONHECIMENTO_AMPLO.md +181 -181
- package/docs/planning/mcp-1.0.0/00_RESUMO_EXECUTIVO_AUDITORIA_MENU.md +118 -0
- package/docs/planning/mcp-1.0.0/01_MATRIZ_TESTES_MENU_E_RESULTADOS.md +250 -0
- package/docs/planning/mcp-1.0.0/02_PLANO_CORRECAO_ATIVAR_SKILL_APRENDIDA.md +200 -0
- package/docs/planning/mcp-1.0.0/03_PLANO_COMPATIBILIDADE_WINDOWS_LINUX_MACOS.md +167 -0
- package/docs/planning/mcp-1.0.0/04_PLANO_UI_CYBERPUNK_PIXEL_ART_E_PERFORMANCE.md +165 -0
- package/docs/planning/mcp-1.0.0/05_PROMPT_TASK_EXECUCAO_CORRECOES.md +151 -0
- package/docs/planning/mcp-1.0.0/06_CHECKLIST_REGRESSAO_PRE_RELEASE.md +159 -0
- package/docs/planning/mcp-1.0.0/07_RELATORIO_APLICACAO_CORRECOES_MENU_SKILL_MASTER.md +136 -0
- package/docs/planning/mcp-1.0.0/08_AUDITORIA_CRITICA_MENU_NOTA_E_DNA_REFINADO.md +184 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/00_PROMPT_TASK_MASTER_NOTA_10_10.md +103 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/01_PROMPT_TASK_FINE_HELIX_DNA.md +116 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/02_PROMPT_TASK_DNA_HERO_BOOT_AND_MOTION.md +109 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/03_PROMPT_TASK_MENU_UX_HELP_ERROR_COPY.md +99 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/04_PROMPT_TASK_EVIDENCE_RENDERER_1_0_0.md +97 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/05_PROMPT_TASK_CROSS_PLATFORM_UTF8_MOJIBAKE.md +99 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/06_PROMPT_TASK_VISUAL_REGRESSION_QA.md +105 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/07_PROMPT_TASK_PRE_RELEASE_SCORE_GATE_10_10.md +104 -0
- package/docs/planning/mcp-1.0.0/prompt-tasks-nota-10-10/README_ORDEM_EXECUCAO_NOTA_10_10.md +77 -0
- package/docs/prompt-tasks/PROMPT_TASK_001_BOOTSTRAP_SKILL_MASTER_MCP.md +6 -6
- package/docs/prompt-tasks/PROMPT_TASK_002_AUTO_UPDATE_LAUNCHER.md +6 -6
- package/docs/prompt-tasks/PROMPT_TASK_003_REMOTE_MANIFEST_AND_RELEASES.md +6 -6
- package/docs/prompt-tasks/PROMPT_TASK_004_MULTI_USER_DISTRIBUTION.md +6 -6
- package/docs/prompt-tasks/PROMPT_TASK_005_SECURITY_AND_QUALITY_GATE.md +6 -6
- package/docs/prompt-tasks/PROMPT_TASK_006_MASTER_ACIONAMENTO_APRENDIZADO.md +83 -83
- package/docs/prompt-tasks/PROMPT_TASK_007_PERSONA_ORQUESTRADORA.md +88 -88
- package/docs/prompt-tasks/PROMPT_TASK_008_PROMPT_ROUTER_MODOS_ATIVACAO.md +156 -156
- package/docs/prompt-tasks/PROMPT_TASK_009_PIPELINE_APRENDIZADO_SUCESSO.md +105 -105
- package/docs/prompt-tasks/PROMPT_TASK_010_EVALS_GOVERNANCA_ATIVACAO.md +119 -119
- package/docs/prompt-tasks/PROMPT_TASK_011_MENU_NOTIFICACOES_NOTION.md +120 -120
- package/docs/prompt-tasks/PROMPT_TASK_012_MENU_CYBERPUNK_PIXEL_FRAME.md +123 -123
- package/docs/prompt-tasks/PROMPT_TASK_013_MENU_FLUID_DNA_ANIMATION.md +114 -114
- package/docs/prompt-tasks/PROMPT_TASK_014_MENU_FUNCTIONAL_PARITY_QA.md +157 -157
- package/docs/prompt-tasks/PROMPT_TASK_015_TRANSFER_RELEASE_HANDOFF.md +127 -127
- package/docs/prompt-tasks/PROMPT_TASK_016_CROSS_PLATFORM_MCP_AUTH_REGISTRATION.md +107 -107
- package/docs/prompt-tasks/PROMPT_TASK_018_NPM_PUBLISH_2FA_SETUP.md +80 -80
- package/docs/prompt-tasks/PROMPT_TASK_019_TOKEN_ECONOMY_GLOBAL_SKILLS.md +56 -0
- package/docs/prompt-tasks/PROMPT_TASK_MASTER_EXECUTOR.md +6 -6
- package/docs/skill-candidates/v0.0.10/cli-creator/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/cli-creator/SKILL.md +160 -160
- package/docs/skill-candidates/v0.0.10/cli-creator/agents/openai.yaml +4 -4
- package/docs/skill-candidates/v0.0.10/cli-creator/references/agent-cli-patterns.md +154 -154
- package/docs/skill-candidates/v0.0.10/developer-workstation-ops/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.10/figma/LICENSE.txt +1 -1
- package/docs/skill-candidates/v0.0.10/figma/SKILL.md +42 -42
- package/docs/skill-candidates/v0.0.10/figma/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma/references/figma-mcp-config.md +35 -35
- package/docs/skill-candidates/v0.0.10/figma/references/figma-tools-and-prompts.md +34 -34
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/LICENSE.TXT +1 -1
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/SKILL.md +349 -349
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/references/mapping-checklist.md +7 -7
- package/docs/skill-candidates/v0.0.10/figma-code-connect-components/scripts/normalize_node_id.py +25 -25
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/LICENSE.TXT +1 -1
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/SKILL.md +537 -537
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/references/rule-template.md +15 -15
- package/docs/skill-candidates/v0.0.10/figma-create-design-system-rules/scripts/check_agents_md.sh +9 -9
- package/docs/skill-candidates/v0.0.10/figma-generate-design/LICENSE.TXT +1 -1
- package/docs/skill-candidates/v0.0.10/figma-generate-design/SKILL.md +341 -341
- package/docs/skill-candidates/v0.0.10/figma-generate-design/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-generate-design/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-generate-design/maintainers.yml +1 -1
- package/docs/skill-candidates/v0.0.10/figma-generate-library/LICENSE.TXT +1 -1
- package/docs/skill-candidates/v0.0.10/figma-generate-library/SKILL.md +314 -314
- package/docs/skill-candidates/v0.0.10/figma-generate-library/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-generate-library/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-generate-library/maintainers.yml +3 -3
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/code-connect-setup.md +260 -260
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/component-creation.md +1014 -1014
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/discovery-phase.md +518 -518
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/documentation-creation.md +834 -834
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/error-recovery.md +540 -540
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/naming-conventions.md +527 -527
- package/docs/skill-candidates/v0.0.10/figma-generate-library/references/token-creation.md +962 -962
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/bindVariablesToComponent.js +110 -110
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/cleanupOrphans.js +127 -127
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createComponentWithVariants.js +148 -148
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createDocumentationPage.js +139 -139
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createSemanticTokens.js +108 -108
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/createVariableCollection.js +49 -49
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/inspectFileStructure.js +121 -121
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/rehydrateState.js +92 -92
- package/docs/skill-candidates/v0.0.10/figma-generate-library/scripts/validateCreation.js +83 -83
- package/docs/skill-candidates/v0.0.10/figma-implement-design/LICENSE.txt +1 -1
- package/docs/skill-candidates/v0.0.10/figma-implement-design/SKILL.md +258 -258
- package/docs/skill-candidates/v0.0.10/figma-implement-design/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-implement-design/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-use/LICENSE.TXT +1 -1
- package/docs/skill-candidates/v0.0.10/figma-use/SKILL.md +233 -233
- package/docs/skill-candidates/v0.0.10/figma-use/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/figma-use/assets/figma-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/figma-use/assets/icon.svg +28 -28
- package/docs/skill-candidates/v0.0.10/figma-use/maintainers.yml +1 -1
- package/docs/skill-candidates/v0.0.10/figma-use/references/api-reference.md +301 -301
- package/docs/skill-candidates/v0.0.10/figma-use/references/common-patterns.md +512 -512
- package/docs/skill-candidates/v0.0.10/figma-use/references/component-patterns.md +488 -488
- package/docs/skill-candidates/v0.0.10/figma-use/references/effect-style-patterns.md +123 -123
- package/docs/skill-candidates/v0.0.10/figma-use/references/gotchas.md +599 -599
- package/docs/skill-candidates/v0.0.10/figma-use/references/maintainers.yml +12 -12
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-patterns.md +513 -513
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.d.ts +11293 -11293
- package/docs/skill-candidates/v0.0.10/figma-use/references/plugin-api-standalone.index.md +441 -441
- package/docs/skill-candidates/v0.0.10/figma-use/references/text-style-patterns.md +203 -203
- package/docs/skill-candidates/v0.0.10/figma-use/references/validation-and-recovery.md +109 -109
- package/docs/skill-candidates/v0.0.10/figma-use/references/variable-patterns.md +354 -354
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/maintainers.yml +9 -9
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--creating.md +17 -17
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components--using.md +17 -17
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-components.md +50 -50
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-effect-styles.md +52 -52
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-text-styles.md +90 -90
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--creating.md +13 -13
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables--using.md +13 -13
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds-variables.md +64 -64
- package/docs/skill-candidates/v0.0.10/figma-use/references/working-with-design-systems/wwds.md +41 -41
- package/docs/skill-candidates/v0.0.10/frontend-design/LICENSE.txt +177 -177
- package/docs/skill-candidates/v0.0.10/frontend-design/SKILL.md +55 -55
- package/docs/skill-candidates/v0.0.10/frontend-ui-ux-systems/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.10/github/SKILL.md +74 -74
- package/docs/skill-candidates/v0.0.10/github/agents/openai.yaml +6 -6
- package/docs/skill-candidates/v0.0.10/github/assets/github-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/image-graphic-design-rendering/SKILL.md +28 -28
- package/docs/skill-candidates/v0.0.10/language-quality-pt-en-fr-it-ru/SKILL.md +28 -28
- package/docs/skill-candidates/v0.0.10/math-physics-reasoning/SKILL.md +28 -28
- package/docs/skill-candidates/v0.0.10/mcp-builder/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/mcp-builder/SKILL.md +236 -236
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/evaluation.md +601 -601
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/mcp_best_practices.md +249 -249
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/node_mcp_server.md +969 -969
- package/docs/skill-candidates/v0.0.10/mcp-builder/reference/python_mcp_server.md +718 -718
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/connections.py +151 -151
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/evaluation.py +373 -373
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/example_evaluation.xml +22 -22
- package/docs/skill-candidates/v0.0.10/mcp-builder/scripts/requirements.txt +2 -2
- package/docs/skill-candidates/v0.0.10/mcp-client-readiness/SKILL.md +31 -31
- package/docs/skill-candidates/v0.0.10/openai-docs/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/openai-docs/SKILL.md +161 -161
- package/docs/skill-candidates/v0.0.10/openai-docs/agents/openai.yaml +14 -14
- package/docs/skill-candidates/v0.0.10/openai-docs/assets/openai-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/openai-docs/references/latest-model.md +37 -37
- package/docs/skill-candidates/v0.0.10/openai-docs/references/prompting-guide.md +244 -244
- package/docs/skill-candidates/v0.0.10/openai-docs/references/upgrade-guide.md +181 -181
- package/docs/skill-candidates/v0.0.10/openai-docs/scripts/fetch-codex-manual.mjs +598 -598
- package/docs/skill-candidates/v0.0.10/openai-docs/scripts/resolve-latest-model-info.js +147 -147
- package/docs/skill-candidates/v0.0.10/playwright/NOTICE.txt +14 -14
- package/docs/skill-candidates/v0.0.10/playwright/SKILL.md +147 -147
- package/docs/skill-candidates/v0.0.10/playwright/agents/openai.yaml +6 -6
- package/docs/skill-candidates/v0.0.10/playwright/assets/playwright-small.svg +3 -3
- package/docs/skill-candidates/v0.0.10/playwright/references/cli.md +116 -116
- package/docs/skill-candidates/v0.0.10/playwright/references/workflows.md +95 -95
- package/docs/skill-candidates/v0.0.10/playwright/scripts/playwright_cli.sh +25 -25
- package/docs/skill-candidates/v0.0.10/polyglot-backend-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.10/screenshot/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/screenshot/SKILL.md +267 -267
- package/docs/skill-candidates/v0.0.10/screenshot/agents/openai.yaml +6 -6
- package/docs/skill-candidates/v0.0.10/screenshot/assets/screenshot-small.svg +5 -5
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/ensure_macos_permissions.sh +54 -54
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_display_info.swift +22 -22
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_permissions.swift +40 -40
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/macos_window_info.swift +126 -126
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.ps1 +163 -163
- package/docs/skill-candidates/v0.0.10/screenshot/scripts/take_screenshot.py +585 -585
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/SKILL.md +62 -62
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/agents/openai.yaml +4 -4
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/activation-policy.md +77 -77
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/human-approval-policy.md +83 -83
- package/docs/skill-candidates/v0.0.10/skill-master-orchestrator/references/persona-dev-senior-master.md +46 -46
- package/docs/skill-candidates/v0.0.10/terminal-menu-operations/SKILL.md +30 -30
- package/docs/skill-candidates/v0.0.10/terminal-pixel-art-tui/SKILL.md +43 -43
- package/docs/skill-candidates/v0.0.10/webapp-testing/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/webapp-testing/SKILL.md +95 -95
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/console_logging.py +34 -34
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/element_discovery.py +39 -39
- package/docs/skill-candidates/v0.0.10/webapp-testing/examples/static_html_automation.py +32 -32
- package/docs/skill-candidates/v0.0.10/webapp-testing/scripts/with_server.py +105 -105
- package/docs/skill-candidates/v0.0.10/winui-app/LICENSE.txt +201 -201
- package/docs/skill-candidates/v0.0.10/winui-app/SKILL.md +94 -94
- package/docs/skill-candidates/v0.0.10/winui-app/agents/openai.yaml +5 -5
- package/docs/skill-candidates/v0.0.10/winui-app/config.yaml +50 -50
- package/docs/skill-candidates/v0.0.10/winui-app/references/_sections.md +96 -96
- package/docs/skill-candidates/v0.0.10/winui-app/references/accessibility-input-and-localization.md +51 -51
- package/docs/skill-candidates/v0.0.10/winui-app/references/build-run-and-launch-verification.md +72 -72
- package/docs/skill-candidates/v0.0.10/winui-app/references/community-toolkit-controls-and-helpers.md +57 -57
- package/docs/skill-candidates/v0.0.10/winui-app/references/controls-layout-and-adaptive-ui.md +84 -84
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-environment-audit-and-remediation.md +82 -82
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-setup-and-project-selection.md +67 -67
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-template-first-recovery.md +62 -62
- package/docs/skill-candidates/v0.0.10/winui-app/references/foundation-winui-app-structure.md +62 -62
- package/docs/skill-candidates/v0.0.10/winui-app/references/motion-animations-and-polish.md +45 -45
- package/docs/skill-candidates/v0.0.10/winui-app/references/performance-diagnostics-and-responsiveness.md +46 -46
- package/docs/skill-candidates/v0.0.10/winui-app/references/sample-source-map.md +37 -37
- package/docs/skill-candidates/v0.0.10/winui-app/references/shell-navigation-and-windowing.md +67 -67
- package/docs/skill-candidates/v0.0.10/winui-app/references/styling-theming-materials-and-icons.md +71 -71
- package/docs/skill-candidates/v0.0.10/winui-app/references/testing-debugging-and-review-checklists.md +77 -77
- package/docs/skill-candidates/v0.0.10/winui-app/references/windows-app-sdk-lifecycle-notifications-and-deployment.md +52 -52
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/SKILL.md +398 -398
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/common-patterns.md +330 -330
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/complete-examples.md +871 -871
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/component-patterns.md +501 -501
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/data-fetching.md +766 -766
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/file-organization.md +501 -501
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/loading-and-error-states.md +500 -500
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/performance.md +405 -405
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/routing-guide.md +363 -363
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/styling-guide.md +427 -427
- package/docs/skill-candidates/v0.0.11/frontend-dev-guidelines/resources/typescript-standards.md +417 -417
- package/docs/skill-candidates/v0.0.11/git-version-control-ops/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/go-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/java-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/javascript-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/json-contract-design/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/multi-client-mcp-ops/SKILL.md +36 -36
- package/docs/skill-candidates/v0.0.11/nextjs/SKILL.md +745 -745
- package/docs/skill-candidates/v0.0.11/nextjs/agents/openai.yaml +3 -3
- package/docs/skill-candidates/v0.0.11/nextjs/references/app-router-files.md +94 -94
- package/docs/skill-candidates/v0.0.11/python-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/ruby-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/senior-fullstack/SKILL.md +209 -209
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/architecture_patterns.md +103 -103
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/development_workflows.md +103 -103
- package/docs/skill-candidates/v0.0.11/senior-fullstack/references/tech_stack_guide.md +103 -103
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/code_quality_analyzer.py +114 -114
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/fullstack_scaffolder.py +114 -114
- package/docs/skill-candidates/v0.0.11/senior-fullstack/scripts/project_scaffolder.py +114 -114
- package/docs/skill-candidates/v0.0.11/shadcn/SKILL.md +573 -573
- package/docs/skill-candidates/v0.0.11/shadcn/agents/openai.yaml +3 -3
- package/docs/skill-candidates/v0.0.11/sql-postgresql-engineering/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/terminal-shell-ops/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/typescript-expert/SKILL.md +429 -429
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/tsconfig-strict.json +91 -91
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/typescript-cheatsheet.md +383 -383
- package/docs/skill-candidates/v0.0.11/typescript-expert/references/utility-types.ts +335 -335
- package/docs/skill-candidates/v0.0.11/typescript-expert/scripts/ts_diagnostic.py +203 -203
- package/docs/skill-candidates/v0.0.11/ui-component-primitives/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/web-mobile-design-systems/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.11/windows-linux-platform-ops/SKILL.md +34 -34
- package/docs/skill-candidates/v0.0.12/context-compression-handoff/SKILL.md +47 -0
- package/docs/skill-candidates/v0.0.12/csharp-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/css-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/go-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/html-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/javascript-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/json-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/prompt-budget-gate/SKILL.md +46 -0
- package/docs/skill-candidates/v0.0.12/python-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/react-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/ruby-senior-master-engineering/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.12/senior-master-code-optimizer/SKILL.md +48 -48
- package/docs/skill-candidates/v0.0.12/sql-senior-master-engineering/SKILL.md +31 -31
- package/docs/skill-candidates/v0.0.12/token-economy-orchestrator/SKILL.md +38 -0
- package/docs/skill-candidates/v0.0.12/typescript-senior-master-engineering/SKILL.md +35 -35
- package/docs/skill-candidates/v0.0.9/ai-ethics-human-dignity/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.9/broad-domain-router/SKILL.md +41 -41
- package/docs/skill-candidates/v0.0.9/catholic-moral-discernment/SKILL.md +31 -31
- package/docs/skill-candidates/v0.0.9/engineering-systems-master/SKILL.md +31 -31
- package/docs/skill-candidates/v0.0.9/language-quality-pt-en-fr/SKILL.md +28 -28
- package/docs/skill-candidates/v0.0.9/math-science-reasoning/SKILL.md +29 -29
- package/docs/skill-candidates/v0.0.9/philosophy-sociology-discernment/SKILL.md +28 -28
- package/docs/skill-candidates/v0.0.9/professional-boundary-triage/SKILL.md +40 -40
- package/docs/skill-candidates/v0.0.9/release-ethics-gate/SKILL.md +32 -32
- package/docs/skill-candidates/v0.0.9/source-authority-reviewer/SKILL.md +31 -31
- package/examples/client-configs/claude-code.commands.md +21 -21
- package/examples/client-configs/claude-code.project.mcp.json +18 -18
- package/examples/client-configs/claude-desktop.macos.json +18 -18
- package/examples/client-configs/claude-desktop.windows.json +20 -20
- package/examples/client-configs/codex.windows.toml +11 -11
- package/examples/client-configs/gemini-code-assist.intellij.mcp.json +18 -18
- package/examples/client-configs/gemini.linux.settings.json +21 -21
- package/examples/client-configs/gemini.windows.settings.json +23 -23
- package/examples/client-configs/generic-stdio.json +16 -16
- package/manifests/channels/beta.json +24 -24
- package/manifests/channels/stable.json +25 -25
- package/network/approved-skills.json +54 -54
- package/network/unapproved-skill-candidates.json +110 -110
- package/package.json +89 -86
- package/scripts/configure-private-registry.mjs +208 -208
- package/scripts/lib/private-registry.mjs +97 -97
- package/scripts/render-menu-evidence.mjs +196 -130
- package/scripts/verify-menu-actions.mjs +112 -107
- package/scripts/verify-menu-visual.mjs +90 -0
- package/sources.json +11 -11
|
@@ -1,512 +1,512 @@
|
|
|
1
|
-
# Common Patterns
|
|
2
|
-
|
|
3
|
-
> Part of the [use_figma skill](../SKILL.md). Working code examples for frequently used operations.
|
|
4
|
-
|
|
5
|
-
## Contents
|
|
6
|
-
|
|
7
|
-
- Basic Script Structure
|
|
8
|
-
- Create a Styled Shape
|
|
9
|
-
- Create a Text Node
|
|
10
|
-
- Create Frame with Auto-Layout
|
|
11
|
-
- Create Variable Collections and Bindings
|
|
12
|
-
- Create Components and Import by Key
|
|
13
|
-
- Component Sets with Variable Modes
|
|
14
|
-
- Multi-Step Large ComponentSet Pattern
|
|
15
|
-
- Read Existing Nodes and Return Data
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
## Basic Script Structure
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
(async () => {
|
|
22
|
-
try {
|
|
23
|
-
const createdNodeIds = []
|
|
24
|
-
const mutatedNodeIds = []
|
|
25
|
-
|
|
26
|
-
// Your code here — track every node you create or mutate
|
|
27
|
-
// createdNodeIds.push(newNode.id)
|
|
28
|
-
// mutatedNodeIds.push(existingNode.id)
|
|
29
|
-
|
|
30
|
-
figma.closePlugin(JSON.stringify({
|
|
31
|
-
success: true,
|
|
32
|
-
createdNodeIds,
|
|
33
|
-
mutatedNodeIds,
|
|
34
|
-
// Plus any other useful data for subsequent calls
|
|
35
|
-
count: createdNodeIds.length
|
|
36
|
-
}))
|
|
37
|
-
} catch (e) {
|
|
38
|
-
figma.closePluginWithFailure(e.toString())
|
|
39
|
-
}
|
|
40
|
-
})()
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Create a Styled Shape
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
(async () => {
|
|
47
|
-
try {
|
|
48
|
-
// Find clear space to the right of existing content
|
|
49
|
-
const page = figma.currentPage
|
|
50
|
-
let maxX = 0
|
|
51
|
-
for (const child of page.children) {
|
|
52
|
-
maxX = Math.max(maxX, child.x + child.width)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const rect = figma.createRectangle()
|
|
56
|
-
rect.name = "Blue Box"
|
|
57
|
-
rect.resize(200, 100)
|
|
58
|
-
rect.fills = [{ type: 'SOLID', color: { r: 0.047, g: 0.549, b: 0.914 } }]
|
|
59
|
-
rect.cornerRadius = 8
|
|
60
|
-
rect.x = maxX + 100 // offset from existing content
|
|
61
|
-
rect.y = 0
|
|
62
|
-
figma.currentPage.appendChild(rect)
|
|
63
|
-
figma.closePlugin(JSON.stringify({ nodeId: rect.id }))
|
|
64
|
-
} catch (e) {
|
|
65
|
-
figma.closePluginWithFailure(e.toString())
|
|
66
|
-
}
|
|
67
|
-
})()
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Create a Text Node
|
|
71
|
-
|
|
72
|
-
```js
|
|
73
|
-
(async () => {
|
|
74
|
-
try {
|
|
75
|
-
// Find clear space to the right of existing content
|
|
76
|
-
const page = figma.currentPage
|
|
77
|
-
let maxX = 0
|
|
78
|
-
for (const child of page.children) {
|
|
79
|
-
maxX = Math.max(maxX, child.x + child.width)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
await figma.loadFontAsync({ family: "Inter", style: "Regular" })
|
|
83
|
-
const text = figma.createText()
|
|
84
|
-
text.characters = "Hello World"
|
|
85
|
-
text.fontSize = 16
|
|
86
|
-
text.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]
|
|
87
|
-
text.textAutoResize = 'WIDTH_AND_HEIGHT'
|
|
88
|
-
text.x = maxX + 100
|
|
89
|
-
text.y = 0
|
|
90
|
-
figma.currentPage.appendChild(text)
|
|
91
|
-
figma.closePlugin(JSON.stringify({ nodeId: text.id }))
|
|
92
|
-
} catch (e) {
|
|
93
|
-
figma.closePluginWithFailure(e.toString())
|
|
94
|
-
}
|
|
95
|
-
})()
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## Create Frame with Auto-Layout
|
|
99
|
-
|
|
100
|
-
```js
|
|
101
|
-
(async () => {
|
|
102
|
-
try {
|
|
103
|
-
// Find clear space to the right of existing content
|
|
104
|
-
const page = figma.currentPage
|
|
105
|
-
let maxX = 0
|
|
106
|
-
for (const child of page.children) {
|
|
107
|
-
maxX = Math.max(maxX, child.x + child.width)
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const frame = figma.createFrame()
|
|
111
|
-
frame.name = "Card"
|
|
112
|
-
frame.layoutMode = 'VERTICAL'
|
|
113
|
-
frame.primaryAxisAlignItems = 'MIN'
|
|
114
|
-
frame.counterAxisAlignItems = 'MIN'
|
|
115
|
-
frame.paddingLeft = 16
|
|
116
|
-
frame.paddingRight = 16
|
|
117
|
-
frame.paddingTop = 12
|
|
118
|
-
frame.paddingBottom = 12
|
|
119
|
-
frame.itemSpacing = 8
|
|
120
|
-
frame.layoutSizingHorizontal = 'HUG'
|
|
121
|
-
frame.layoutSizingVertical = 'HUG'
|
|
122
|
-
frame.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]
|
|
123
|
-
frame.cornerRadius = 8
|
|
124
|
-
frame.x = maxX + 100
|
|
125
|
-
frame.y = 0
|
|
126
|
-
figma.currentPage.appendChild(frame)
|
|
127
|
-
figma.closePlugin(JSON.stringify({ nodeId: frame.id }))
|
|
128
|
-
} catch (e) {
|
|
129
|
-
figma.closePluginWithFailure(e.toString())
|
|
130
|
-
}
|
|
131
|
-
})()
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## Create Variable Collection with Multiple Modes
|
|
135
|
-
|
|
136
|
-
```js
|
|
137
|
-
(async () => {
|
|
138
|
-
try {
|
|
139
|
-
const collection = figma.variables.createVariableCollection("Theme/Colors")
|
|
140
|
-
// Rename the default mode
|
|
141
|
-
collection.renameMode(collection.modes[0].modeId, "Light")
|
|
142
|
-
const darkModeId = collection.addMode("Dark")
|
|
143
|
-
const lightModeId = collection.modes[0].modeId
|
|
144
|
-
|
|
145
|
-
const bgVar = figma.variables.createVariable("bg", collection, "COLOR")
|
|
146
|
-
bgVar.setValueForMode(lightModeId, { r: 1, g: 1, b: 1, a: 1 })
|
|
147
|
-
bgVar.setValueForMode(darkModeId, { r: 0.1, g: 0.1, b: 0.1, a: 1 })
|
|
148
|
-
|
|
149
|
-
const textVar = figma.variables.createVariable("text", collection, "COLOR")
|
|
150
|
-
textVar.setValueForMode(lightModeId, { r: 0, g: 0, b: 0, a: 1 })
|
|
151
|
-
textVar.setValueForMode(darkModeId, { r: 1, g: 1, b: 1, a: 1 })
|
|
152
|
-
|
|
153
|
-
figma.closePlugin(JSON.stringify({
|
|
154
|
-
collectionId: collection.id,
|
|
155
|
-
lightModeId,
|
|
156
|
-
darkModeId,
|
|
157
|
-
bgVarId: bgVar.id,
|
|
158
|
-
textVarId: textVar.id
|
|
159
|
-
}))
|
|
160
|
-
} catch (e) {
|
|
161
|
-
figma.closePluginWithFailure(e.toString())
|
|
162
|
-
}
|
|
163
|
-
})()
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
## Bind Color Variable to a Fill
|
|
167
|
-
|
|
168
|
-
```js
|
|
169
|
-
(async () => {
|
|
170
|
-
try {
|
|
171
|
-
const variable = figma.variables.getVariableById("VariableID:1:2")
|
|
172
|
-
const rect = figma.createRectangle()
|
|
173
|
-
const basePaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
|
|
174
|
-
|
|
175
|
-
// setBoundVariableForPaint returns a NEW paint — capture it!
|
|
176
|
-
const boundPaint = figma.variables.setBoundVariableForPaint(basePaint, "color", variable)
|
|
177
|
-
rect.fills = [boundPaint]
|
|
178
|
-
|
|
179
|
-
figma.closePlugin(JSON.stringify({ nodeId: rect.id }))
|
|
180
|
-
} catch (e) {
|
|
181
|
-
figma.closePluginWithFailure(e.toString())
|
|
182
|
-
}
|
|
183
|
-
})()
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
## Create Component Variants with Component Properties
|
|
187
|
-
|
|
188
|
-
Component properties (TEXT, BOOLEAN, INSTANCE_SWAP) MUST be added inside the per-variant loop, BEFORE `combineAsVariants`. The component set inherits them from its children.
|
|
189
|
-
|
|
190
|
-
```js
|
|
191
|
-
(async () => {
|
|
192
|
-
try {
|
|
193
|
-
await figma.loadFontAsync({ family: "Inter", style: "Regular" })
|
|
194
|
-
|
|
195
|
-
// Assume defaultIconComp is an existing icon component (discovered earlier)
|
|
196
|
-
const defaultIconComp = figma.getNodeById('ICON_COMPONENT_ID')
|
|
197
|
-
|
|
198
|
-
const components = []
|
|
199
|
-
const variants = ["primary", "secondary"]
|
|
200
|
-
|
|
201
|
-
for (const variant of variants) {
|
|
202
|
-
const comp = figma.createComponent()
|
|
203
|
-
comp.name = `variant=${variant}`
|
|
204
|
-
comp.layoutMode = 'HORIZONTAL'
|
|
205
|
-
comp.primaryAxisAlignItems = 'CENTER'
|
|
206
|
-
comp.counterAxisAlignItems = 'CENTER'
|
|
207
|
-
comp.paddingLeft = 12
|
|
208
|
-
comp.paddingRight = 12
|
|
209
|
-
comp.paddingTop = 8
|
|
210
|
-
comp.paddingBottom = 8
|
|
211
|
-
comp.layoutSizingHorizontal = 'HUG'
|
|
212
|
-
comp.layoutSizingVertical = 'HUG'
|
|
213
|
-
comp.cornerRadius = 6
|
|
214
|
-
comp.itemSpacing = 8
|
|
215
|
-
|
|
216
|
-
// TEXT property — label
|
|
217
|
-
const labelKey = comp.addComponentProperty('Label', 'TEXT', 'Button')
|
|
218
|
-
const label = figma.createText()
|
|
219
|
-
label.characters = "Button"
|
|
220
|
-
label.fontSize = 14
|
|
221
|
-
comp.appendChild(label)
|
|
222
|
-
label.componentPropertyReferences = { characters: labelKey }
|
|
223
|
-
|
|
224
|
-
// BOOLEAN + INSTANCE_SWAP — icon slot
|
|
225
|
-
const showIconKey = comp.addComponentProperty('Show Icon', 'BOOLEAN', false)
|
|
226
|
-
const iconSlotKey = comp.addComponentProperty('Icon', 'INSTANCE_SWAP', defaultIconComp.id)
|
|
227
|
-
const iconInstance = defaultIconComp.createInstance()
|
|
228
|
-
comp.insertChild(0, iconInstance) // icon before label
|
|
229
|
-
iconInstance.componentPropertyReferences = {
|
|
230
|
-
visible: showIconKey,
|
|
231
|
-
mainComponent: iconSlotKey
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
components.push(comp)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const componentSet = figma.combineAsVariants(components, figma.currentPage)
|
|
238
|
-
componentSet.name = "Button"
|
|
239
|
-
|
|
240
|
-
// Layout variants in a row after combining (they stack at 0,0 by default)
|
|
241
|
-
const colW = 140
|
|
242
|
-
componentSet.children.forEach((child, i) => {
|
|
243
|
-
child.x = i * colW
|
|
244
|
-
child.y = 0
|
|
245
|
-
})
|
|
246
|
-
// Resize from actual child bounds — formula-based sizing is error-prone
|
|
247
|
-
let maxX = 0, maxY = 0
|
|
248
|
-
for (const c of componentSet.children) {
|
|
249
|
-
maxX = Math.max(maxX, c.x + c.width)
|
|
250
|
-
maxY = Math.max(maxY, c.y + c.height)
|
|
251
|
-
}
|
|
252
|
-
componentSet.resizeWithoutConstraints(maxX + 40, maxY + 40)
|
|
253
|
-
|
|
254
|
-
figma.closePlugin(JSON.stringify({
|
|
255
|
-
componentSetId: componentSet.id,
|
|
256
|
-
componentIds: components.map(c => c.id)
|
|
257
|
-
}))
|
|
258
|
-
} catch (e) {
|
|
259
|
-
figma.closePluginWithFailure(e.toString())
|
|
260
|
-
}
|
|
261
|
-
})()
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
## Import a Component by Key (Team Libraries)
|
|
265
|
-
|
|
266
|
-
`importComponentByKeyAsync` and `importComponentSetByKeyAsync` import components from **team libraries** (not the same file you're working in). For components in the current file, use `figma.getNodeByIdAsync()` or `findOne()`/`findAll()` to locate them directly.
|
|
267
|
-
|
|
268
|
-
```js
|
|
269
|
-
(async () => {
|
|
270
|
-
try {
|
|
271
|
-
// Import a single published component by key
|
|
272
|
-
const comp = await figma.importComponentByKeyAsync("COMPONENT_KEY")
|
|
273
|
-
const instance = comp.createInstance()
|
|
274
|
-
instance.x = 40
|
|
275
|
-
instance.y = 40
|
|
276
|
-
figma.currentPage.appendChild(instance)
|
|
277
|
-
|
|
278
|
-
// Import a published component set by key and select a variant
|
|
279
|
-
const compSet = await figma.importComponentSetByKeyAsync("COMPONENT_SET_KEY")
|
|
280
|
-
const variant =
|
|
281
|
-
compSet.children.find((c) =>
|
|
282
|
-
c.type === "COMPONENT" && c.name.includes("size=md")
|
|
283
|
-
) || compSet.defaultVariant
|
|
284
|
-
|
|
285
|
-
const variantInstance = variant.createInstance()
|
|
286
|
-
variantInstance.x = 240
|
|
287
|
-
variantInstance.y = 40
|
|
288
|
-
figma.currentPage.appendChild(variantInstance)
|
|
289
|
-
|
|
290
|
-
figma.closePlugin(JSON.stringify({
|
|
291
|
-
componentId: comp.id,
|
|
292
|
-
componentSetId: compSet.id,
|
|
293
|
-
placedInstanceIds: [instance.id, variantInstance.id]
|
|
294
|
-
}))
|
|
295
|
-
} catch (e) {
|
|
296
|
-
figma.closePluginWithFailure(e.toString())
|
|
297
|
-
}
|
|
298
|
-
})()
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
## Component Set with Variable Modes (Full Pattern)
|
|
302
|
-
|
|
303
|
-
```js
|
|
304
|
-
(async () => {
|
|
305
|
-
try {
|
|
306
|
-
await figma.loadFontAsync({ family: "Inter", style: "Medium" })
|
|
307
|
-
|
|
308
|
-
// 1. Create color collection with modes per variant
|
|
309
|
-
const colors = figma.variables.createVariableCollection("Component/Colors")
|
|
310
|
-
colors.renameMode(colors.modes[0].modeId, "primary")
|
|
311
|
-
const primaryMode = colors.modes[0].modeId
|
|
312
|
-
const secondaryMode = colors.addMode("secondary")
|
|
313
|
-
|
|
314
|
-
const bgVar = figma.variables.createVariable("bg", colors, "COLOR")
|
|
315
|
-
bgVar.setValueForMode(primaryMode, { r: 0, g: 0.4, b: 0.9, a: 1 })
|
|
316
|
-
bgVar.setValueForMode(secondaryMode, { r: 0, g: 0, b: 0, a: 0 })
|
|
317
|
-
|
|
318
|
-
const textVar = figma.variables.createVariable("text-color", colors, "COLOR")
|
|
319
|
-
textVar.setValueForMode(primaryMode, { r: 1, g: 1, b: 1, a: 1 })
|
|
320
|
-
textVar.setValueForMode(secondaryMode, { r: 0.1, g: 0.1, b: 0.1, a: 1 })
|
|
321
|
-
|
|
322
|
-
// 2. Create components with variable bindings
|
|
323
|
-
const modeMap = { primary: primaryMode, secondary: secondaryMode }
|
|
324
|
-
const components = []
|
|
325
|
-
|
|
326
|
-
for (const [variantName, modeId] of Object.entries(modeMap)) {
|
|
327
|
-
const comp = figma.createComponent()
|
|
328
|
-
comp.name = "variant=" + variantName
|
|
329
|
-
comp.layoutMode = "HORIZONTAL"
|
|
330
|
-
comp.primaryAxisAlignItems = "CENTER"
|
|
331
|
-
comp.counterAxisAlignItems = "CENTER"
|
|
332
|
-
comp.paddingLeft = 12; comp.paddingRight = 12
|
|
333
|
-
comp.layoutSizingHorizontal = "HUG"
|
|
334
|
-
comp.layoutSizingVertical = "HUG"
|
|
335
|
-
comp.cornerRadius = 6
|
|
336
|
-
|
|
337
|
-
// Bind background fill to variable
|
|
338
|
-
const bgPaint = figma.variables.setBoundVariableForPaint(
|
|
339
|
-
{ type: "SOLID", color: { r: 0, g: 0, b: 0 } }, "color", bgVar
|
|
340
|
-
)
|
|
341
|
-
comp.fills = [bgPaint]
|
|
342
|
-
|
|
343
|
-
// Add text with bound color
|
|
344
|
-
const label = figma.createText()
|
|
345
|
-
label.fontName = { family: "Inter", style: "Medium" }
|
|
346
|
-
label.characters = "Button"
|
|
347
|
-
label.fontSize = 14
|
|
348
|
-
const textPaint = figma.variables.setBoundVariableForPaint(
|
|
349
|
-
{ type: "SOLID", color: { r: 0, g: 0, b: 0 } }, "color", textVar
|
|
350
|
-
)
|
|
351
|
-
label.fills = [textPaint]
|
|
352
|
-
comp.appendChild(label)
|
|
353
|
-
|
|
354
|
-
// 3. CRITICAL: Set explicit mode so this variant renders correctly
|
|
355
|
-
comp.setExplicitVariableModeForCollection(colors.id, modeId)
|
|
356
|
-
|
|
357
|
-
components.push(comp)
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// 4. Combine into component set
|
|
361
|
-
const componentSet = figma.combineAsVariants(components, figma.currentPage)
|
|
362
|
-
componentSet.name = "Button"
|
|
363
|
-
|
|
364
|
-
figma.closePlugin(JSON.stringify({
|
|
365
|
-
componentSetId: componentSet.id,
|
|
366
|
-
colorCollectionId: colors.id
|
|
367
|
-
}))
|
|
368
|
-
} catch (e) {
|
|
369
|
-
figma.closePluginWithFailure(e.toString())
|
|
370
|
-
}
|
|
371
|
-
})()
|
|
372
|
-
```
|
|
373
|
-
|
|
374
|
-
## Large ComponentSet with Variable Modes (Multi-Step Pattern)
|
|
375
|
-
|
|
376
|
-
For component sets with many variants (50+), split into multiple `use_figma` calls:
|
|
377
|
-
|
|
378
|
-
**Call 1: Create variable collections and return IDs**
|
|
379
|
-
|
|
380
|
-
```js
|
|
381
|
-
(async () => {
|
|
382
|
-
try {
|
|
383
|
-
// Hex-to-0-1 helper
|
|
384
|
-
const hex = (h) => {
|
|
385
|
-
if (!h) return { r: 0, g: 0, b: 0, a: 0 }; // transparent
|
|
386
|
-
return {
|
|
387
|
-
r: parseInt(h.slice(1,3), 16) / 255,
|
|
388
|
-
g: parseInt(h.slice(3,5), 16) / 255,
|
|
389
|
-
b: parseInt(h.slice(5,7), 16) / 255,
|
|
390
|
-
a: 1
|
|
391
|
-
};
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
const coll = figma.variables.createVariableCollection("MyComponent/Colors");
|
|
395
|
-
coll.renameMode(coll.modes[0].modeId, "mode1");
|
|
396
|
-
const mode2Id = coll.addMode("mode2");
|
|
397
|
-
|
|
398
|
-
// Create variables from data map
|
|
399
|
-
const colorData = { "bg/default": ["#0B6BCB", "#636B74"], /* ... */ };
|
|
400
|
-
const modeOrder = ["mode1", "mode2"];
|
|
401
|
-
const modeIds = { mode1: coll.modes[0].modeId, mode2: mode2Id };
|
|
402
|
-
const varIds = {};
|
|
403
|
-
|
|
404
|
-
for (const [name, values] of Object.entries(colorData)) {
|
|
405
|
-
const v = figma.variables.createVariable(name, coll, "COLOR");
|
|
406
|
-
values.forEach((hex_val, i) => {
|
|
407
|
-
v.setValueForMode(modeIds[modeOrder[i]], hex_val ? hex(hex_val) : { r:0, g:0, b:0, a:0 });
|
|
408
|
-
});
|
|
409
|
-
varIds[name] = v.id;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
// Return ALL IDs — needed by subsequent calls
|
|
413
|
-
figma.closePlugin(JSON.stringify({ collId: coll.id, modeIds, varIds }));
|
|
414
|
-
} catch (e) {
|
|
415
|
-
figma.closePluginWithFailure(e.toString());
|
|
416
|
-
}
|
|
417
|
-
})()
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
**Call 2: Create components using stored IDs, combine and layout**
|
|
421
|
-
|
|
422
|
-
```js
|
|
423
|
-
(async () => {
|
|
424
|
-
try {
|
|
425
|
-
await figma.loadFontAsync({ family: "Inter", style: "Semi Bold" });
|
|
426
|
-
|
|
427
|
-
// Paste IDs from Call 1 as literals
|
|
428
|
-
const collId = "VariableCollectionId:X:Y";
|
|
429
|
-
const modeIds = { mode1: "X:0", mode2: "X:1" };
|
|
430
|
-
const varIds = { /* ... from Call 1 ... */ };
|
|
431
|
-
|
|
432
|
-
const getVar = (id) => figma.variables.getVariableById(id);
|
|
433
|
-
const bindColor = (varId) => figma.variables.setBoundVariableForPaint(
|
|
434
|
-
{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }, 'color', getVar(varId)
|
|
435
|
-
);
|
|
436
|
-
|
|
437
|
-
const components = [];
|
|
438
|
-
for (const mode of ["mode1", "mode2"]) {
|
|
439
|
-
for (const state of ["default", "hover"]) {
|
|
440
|
-
const comp = figma.createComponent();
|
|
441
|
-
comp.name = `mode=${mode}, state=${state}`;
|
|
442
|
-
comp.layoutMode = 'HORIZONTAL';
|
|
443
|
-
comp.primaryAxisAlignItems = 'CENTER';
|
|
444
|
-
comp.counterAxisAlignItems = 'CENTER';
|
|
445
|
-
comp.layoutSizingHorizontal = 'HUG';
|
|
446
|
-
comp.layoutSizingVertical = 'HUG';
|
|
447
|
-
comp.fills = [bindColor(varIds[`bg/${state}`])];
|
|
448
|
-
comp.setExplicitVariableModeForCollection(collId, modeIds[mode]);
|
|
449
|
-
// ... add text children ...
|
|
450
|
-
components.push(comp);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Combine — all children stack at (0,0)!
|
|
455
|
-
const cs = figma.combineAsVariants(components, figma.currentPage);
|
|
456
|
-
cs.name = "MyComponent";
|
|
457
|
-
|
|
458
|
-
// CRITICAL: layout variants in a structured grid mapped to variant axes.
|
|
459
|
-
const stateOrder = ["default", "hover"];
|
|
460
|
-
const modeOrder2 = ["mode1", "mode2"];
|
|
461
|
-
const colW = 140, rowH = 56;
|
|
462
|
-
|
|
463
|
-
for (const child of cs.children) {
|
|
464
|
-
const props = Object.fromEntries(
|
|
465
|
-
child.name.split(', ').map(p => p.split('='))
|
|
466
|
-
);
|
|
467
|
-
const col = stateOrder.indexOf(props.state);
|
|
468
|
-
const row = modeOrder2.indexOf(props.mode);
|
|
469
|
-
child.x = col * colW;
|
|
470
|
-
child.y = row * rowH;
|
|
471
|
-
}
|
|
472
|
-
// Resize from actual child bounds
|
|
473
|
-
let maxX = 0, maxY = 0;
|
|
474
|
-
for (const child of cs.children) {
|
|
475
|
-
maxX = Math.max(maxX, child.x + child.width);
|
|
476
|
-
maxY = Math.max(maxY, child.y + child.height);
|
|
477
|
-
}
|
|
478
|
-
cs.resizeWithoutConstraints(maxX + 40, maxY + 40);
|
|
479
|
-
|
|
480
|
-
// Wrap in section
|
|
481
|
-
const section = figma.createSection();
|
|
482
|
-
section.name = "MyComponent Section";
|
|
483
|
-
section.appendChild(cs);
|
|
484
|
-
section.resizeWithoutConstraints(cs.width + 200, cs.height + 200);
|
|
485
|
-
|
|
486
|
-
figma.closePlugin(JSON.stringify({ csId: cs.id, count: components.length }));
|
|
487
|
-
} catch (e) {
|
|
488
|
-
figma.closePluginWithFailure(e.toString());
|
|
489
|
-
}
|
|
490
|
-
})()
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
## Read Existing Nodes and Return Data
|
|
494
|
-
|
|
495
|
-
```js
|
|
496
|
-
(async () => {
|
|
497
|
-
try {
|
|
498
|
-
const page = figma.currentPage
|
|
499
|
-
const nodes = page.findAll(n => n.type === 'FRAME')
|
|
500
|
-
const data = nodes.map(n => ({
|
|
501
|
-
id: n.id,
|
|
502
|
-
name: n.name,
|
|
503
|
-
width: n.width,
|
|
504
|
-
height: n.height,
|
|
505
|
-
childCount: n.children?.length || 0
|
|
506
|
-
}))
|
|
507
|
-
figma.closePlugin(JSON.stringify({ frames: data }))
|
|
508
|
-
} catch (e) {
|
|
509
|
-
figma.closePluginWithFailure(e.toString())
|
|
510
|
-
}
|
|
511
|
-
})()
|
|
512
|
-
```
|
|
1
|
+
# Common Patterns
|
|
2
|
+
|
|
3
|
+
> Part of the [use_figma skill](../SKILL.md). Working code examples for frequently used operations.
|
|
4
|
+
|
|
5
|
+
## Contents
|
|
6
|
+
|
|
7
|
+
- Basic Script Structure
|
|
8
|
+
- Create a Styled Shape
|
|
9
|
+
- Create a Text Node
|
|
10
|
+
- Create Frame with Auto-Layout
|
|
11
|
+
- Create Variable Collections and Bindings
|
|
12
|
+
- Create Components and Import by Key
|
|
13
|
+
- Component Sets with Variable Modes
|
|
14
|
+
- Multi-Step Large ComponentSet Pattern
|
|
15
|
+
- Read Existing Nodes and Return Data
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
## Basic Script Structure
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
(async () => {
|
|
22
|
+
try {
|
|
23
|
+
const createdNodeIds = []
|
|
24
|
+
const mutatedNodeIds = []
|
|
25
|
+
|
|
26
|
+
// Your code here — track every node you create or mutate
|
|
27
|
+
// createdNodeIds.push(newNode.id)
|
|
28
|
+
// mutatedNodeIds.push(existingNode.id)
|
|
29
|
+
|
|
30
|
+
figma.closePlugin(JSON.stringify({
|
|
31
|
+
success: true,
|
|
32
|
+
createdNodeIds,
|
|
33
|
+
mutatedNodeIds,
|
|
34
|
+
// Plus any other useful data for subsequent calls
|
|
35
|
+
count: createdNodeIds.length
|
|
36
|
+
}))
|
|
37
|
+
} catch (e) {
|
|
38
|
+
figma.closePluginWithFailure(e.toString())
|
|
39
|
+
}
|
|
40
|
+
})()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Create a Styled Shape
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
(async () => {
|
|
47
|
+
try {
|
|
48
|
+
// Find clear space to the right of existing content
|
|
49
|
+
const page = figma.currentPage
|
|
50
|
+
let maxX = 0
|
|
51
|
+
for (const child of page.children) {
|
|
52
|
+
maxX = Math.max(maxX, child.x + child.width)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const rect = figma.createRectangle()
|
|
56
|
+
rect.name = "Blue Box"
|
|
57
|
+
rect.resize(200, 100)
|
|
58
|
+
rect.fills = [{ type: 'SOLID', color: { r: 0.047, g: 0.549, b: 0.914 } }]
|
|
59
|
+
rect.cornerRadius = 8
|
|
60
|
+
rect.x = maxX + 100 // offset from existing content
|
|
61
|
+
rect.y = 0
|
|
62
|
+
figma.currentPage.appendChild(rect)
|
|
63
|
+
figma.closePlugin(JSON.stringify({ nodeId: rect.id }))
|
|
64
|
+
} catch (e) {
|
|
65
|
+
figma.closePluginWithFailure(e.toString())
|
|
66
|
+
}
|
|
67
|
+
})()
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Create a Text Node
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
(async () => {
|
|
74
|
+
try {
|
|
75
|
+
// Find clear space to the right of existing content
|
|
76
|
+
const page = figma.currentPage
|
|
77
|
+
let maxX = 0
|
|
78
|
+
for (const child of page.children) {
|
|
79
|
+
maxX = Math.max(maxX, child.x + child.width)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await figma.loadFontAsync({ family: "Inter", style: "Regular" })
|
|
83
|
+
const text = figma.createText()
|
|
84
|
+
text.characters = "Hello World"
|
|
85
|
+
text.fontSize = 16
|
|
86
|
+
text.fills = [{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }]
|
|
87
|
+
text.textAutoResize = 'WIDTH_AND_HEIGHT'
|
|
88
|
+
text.x = maxX + 100
|
|
89
|
+
text.y = 0
|
|
90
|
+
figma.currentPage.appendChild(text)
|
|
91
|
+
figma.closePlugin(JSON.stringify({ nodeId: text.id }))
|
|
92
|
+
} catch (e) {
|
|
93
|
+
figma.closePluginWithFailure(e.toString())
|
|
94
|
+
}
|
|
95
|
+
})()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Create Frame with Auto-Layout
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
(async () => {
|
|
102
|
+
try {
|
|
103
|
+
// Find clear space to the right of existing content
|
|
104
|
+
const page = figma.currentPage
|
|
105
|
+
let maxX = 0
|
|
106
|
+
for (const child of page.children) {
|
|
107
|
+
maxX = Math.max(maxX, child.x + child.width)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const frame = figma.createFrame()
|
|
111
|
+
frame.name = "Card"
|
|
112
|
+
frame.layoutMode = 'VERTICAL'
|
|
113
|
+
frame.primaryAxisAlignItems = 'MIN'
|
|
114
|
+
frame.counterAxisAlignItems = 'MIN'
|
|
115
|
+
frame.paddingLeft = 16
|
|
116
|
+
frame.paddingRight = 16
|
|
117
|
+
frame.paddingTop = 12
|
|
118
|
+
frame.paddingBottom = 12
|
|
119
|
+
frame.itemSpacing = 8
|
|
120
|
+
frame.layoutSizingHorizontal = 'HUG'
|
|
121
|
+
frame.layoutSizingVertical = 'HUG'
|
|
122
|
+
frame.fills = [{ type: 'SOLID', color: { r: 1, g: 1, b: 1 } }]
|
|
123
|
+
frame.cornerRadius = 8
|
|
124
|
+
frame.x = maxX + 100
|
|
125
|
+
frame.y = 0
|
|
126
|
+
figma.currentPage.appendChild(frame)
|
|
127
|
+
figma.closePlugin(JSON.stringify({ nodeId: frame.id }))
|
|
128
|
+
} catch (e) {
|
|
129
|
+
figma.closePluginWithFailure(e.toString())
|
|
130
|
+
}
|
|
131
|
+
})()
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Create Variable Collection with Multiple Modes
|
|
135
|
+
|
|
136
|
+
```js
|
|
137
|
+
(async () => {
|
|
138
|
+
try {
|
|
139
|
+
const collection = figma.variables.createVariableCollection("Theme/Colors")
|
|
140
|
+
// Rename the default mode
|
|
141
|
+
collection.renameMode(collection.modes[0].modeId, "Light")
|
|
142
|
+
const darkModeId = collection.addMode("Dark")
|
|
143
|
+
const lightModeId = collection.modes[0].modeId
|
|
144
|
+
|
|
145
|
+
const bgVar = figma.variables.createVariable("bg", collection, "COLOR")
|
|
146
|
+
bgVar.setValueForMode(lightModeId, { r: 1, g: 1, b: 1, a: 1 })
|
|
147
|
+
bgVar.setValueForMode(darkModeId, { r: 0.1, g: 0.1, b: 0.1, a: 1 })
|
|
148
|
+
|
|
149
|
+
const textVar = figma.variables.createVariable("text", collection, "COLOR")
|
|
150
|
+
textVar.setValueForMode(lightModeId, { r: 0, g: 0, b: 0, a: 1 })
|
|
151
|
+
textVar.setValueForMode(darkModeId, { r: 1, g: 1, b: 1, a: 1 })
|
|
152
|
+
|
|
153
|
+
figma.closePlugin(JSON.stringify({
|
|
154
|
+
collectionId: collection.id,
|
|
155
|
+
lightModeId,
|
|
156
|
+
darkModeId,
|
|
157
|
+
bgVarId: bgVar.id,
|
|
158
|
+
textVarId: textVar.id
|
|
159
|
+
}))
|
|
160
|
+
} catch (e) {
|
|
161
|
+
figma.closePluginWithFailure(e.toString())
|
|
162
|
+
}
|
|
163
|
+
})()
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Bind Color Variable to a Fill
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
(async () => {
|
|
170
|
+
try {
|
|
171
|
+
const variable = figma.variables.getVariableById("VariableID:1:2")
|
|
172
|
+
const rect = figma.createRectangle()
|
|
173
|
+
const basePaint = { type: 'SOLID', color: { r: 0, g: 0, b: 0 } }
|
|
174
|
+
|
|
175
|
+
// setBoundVariableForPaint returns a NEW paint — capture it!
|
|
176
|
+
const boundPaint = figma.variables.setBoundVariableForPaint(basePaint, "color", variable)
|
|
177
|
+
rect.fills = [boundPaint]
|
|
178
|
+
|
|
179
|
+
figma.closePlugin(JSON.stringify({ nodeId: rect.id }))
|
|
180
|
+
} catch (e) {
|
|
181
|
+
figma.closePluginWithFailure(e.toString())
|
|
182
|
+
}
|
|
183
|
+
})()
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Create Component Variants with Component Properties
|
|
187
|
+
|
|
188
|
+
Component properties (TEXT, BOOLEAN, INSTANCE_SWAP) MUST be added inside the per-variant loop, BEFORE `combineAsVariants`. The component set inherits them from its children.
|
|
189
|
+
|
|
190
|
+
```js
|
|
191
|
+
(async () => {
|
|
192
|
+
try {
|
|
193
|
+
await figma.loadFontAsync({ family: "Inter", style: "Regular" })
|
|
194
|
+
|
|
195
|
+
// Assume defaultIconComp is an existing icon component (discovered earlier)
|
|
196
|
+
const defaultIconComp = figma.getNodeById('ICON_COMPONENT_ID')
|
|
197
|
+
|
|
198
|
+
const components = []
|
|
199
|
+
const variants = ["primary", "secondary"]
|
|
200
|
+
|
|
201
|
+
for (const variant of variants) {
|
|
202
|
+
const comp = figma.createComponent()
|
|
203
|
+
comp.name = `variant=${variant}`
|
|
204
|
+
comp.layoutMode = 'HORIZONTAL'
|
|
205
|
+
comp.primaryAxisAlignItems = 'CENTER'
|
|
206
|
+
comp.counterAxisAlignItems = 'CENTER'
|
|
207
|
+
comp.paddingLeft = 12
|
|
208
|
+
comp.paddingRight = 12
|
|
209
|
+
comp.paddingTop = 8
|
|
210
|
+
comp.paddingBottom = 8
|
|
211
|
+
comp.layoutSizingHorizontal = 'HUG'
|
|
212
|
+
comp.layoutSizingVertical = 'HUG'
|
|
213
|
+
comp.cornerRadius = 6
|
|
214
|
+
comp.itemSpacing = 8
|
|
215
|
+
|
|
216
|
+
// TEXT property — label
|
|
217
|
+
const labelKey = comp.addComponentProperty('Label', 'TEXT', 'Button')
|
|
218
|
+
const label = figma.createText()
|
|
219
|
+
label.characters = "Button"
|
|
220
|
+
label.fontSize = 14
|
|
221
|
+
comp.appendChild(label)
|
|
222
|
+
label.componentPropertyReferences = { characters: labelKey }
|
|
223
|
+
|
|
224
|
+
// BOOLEAN + INSTANCE_SWAP — icon slot
|
|
225
|
+
const showIconKey = comp.addComponentProperty('Show Icon', 'BOOLEAN', false)
|
|
226
|
+
const iconSlotKey = comp.addComponentProperty('Icon', 'INSTANCE_SWAP', defaultIconComp.id)
|
|
227
|
+
const iconInstance = defaultIconComp.createInstance()
|
|
228
|
+
comp.insertChild(0, iconInstance) // icon before label
|
|
229
|
+
iconInstance.componentPropertyReferences = {
|
|
230
|
+
visible: showIconKey,
|
|
231
|
+
mainComponent: iconSlotKey
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
components.push(comp)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const componentSet = figma.combineAsVariants(components, figma.currentPage)
|
|
238
|
+
componentSet.name = "Button"
|
|
239
|
+
|
|
240
|
+
// Layout variants in a row after combining (they stack at 0,0 by default)
|
|
241
|
+
const colW = 140
|
|
242
|
+
componentSet.children.forEach((child, i) => {
|
|
243
|
+
child.x = i * colW
|
|
244
|
+
child.y = 0
|
|
245
|
+
})
|
|
246
|
+
// Resize from actual child bounds — formula-based sizing is error-prone
|
|
247
|
+
let maxX = 0, maxY = 0
|
|
248
|
+
for (const c of componentSet.children) {
|
|
249
|
+
maxX = Math.max(maxX, c.x + c.width)
|
|
250
|
+
maxY = Math.max(maxY, c.y + c.height)
|
|
251
|
+
}
|
|
252
|
+
componentSet.resizeWithoutConstraints(maxX + 40, maxY + 40)
|
|
253
|
+
|
|
254
|
+
figma.closePlugin(JSON.stringify({
|
|
255
|
+
componentSetId: componentSet.id,
|
|
256
|
+
componentIds: components.map(c => c.id)
|
|
257
|
+
}))
|
|
258
|
+
} catch (e) {
|
|
259
|
+
figma.closePluginWithFailure(e.toString())
|
|
260
|
+
}
|
|
261
|
+
})()
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Import a Component by Key (Team Libraries)
|
|
265
|
+
|
|
266
|
+
`importComponentByKeyAsync` and `importComponentSetByKeyAsync` import components from **team libraries** (not the same file you're working in). For components in the current file, use `figma.getNodeByIdAsync()` or `findOne()`/`findAll()` to locate them directly.
|
|
267
|
+
|
|
268
|
+
```js
|
|
269
|
+
(async () => {
|
|
270
|
+
try {
|
|
271
|
+
// Import a single published component by key
|
|
272
|
+
const comp = await figma.importComponentByKeyAsync("COMPONENT_KEY")
|
|
273
|
+
const instance = comp.createInstance()
|
|
274
|
+
instance.x = 40
|
|
275
|
+
instance.y = 40
|
|
276
|
+
figma.currentPage.appendChild(instance)
|
|
277
|
+
|
|
278
|
+
// Import a published component set by key and select a variant
|
|
279
|
+
const compSet = await figma.importComponentSetByKeyAsync("COMPONENT_SET_KEY")
|
|
280
|
+
const variant =
|
|
281
|
+
compSet.children.find((c) =>
|
|
282
|
+
c.type === "COMPONENT" && c.name.includes("size=md")
|
|
283
|
+
) || compSet.defaultVariant
|
|
284
|
+
|
|
285
|
+
const variantInstance = variant.createInstance()
|
|
286
|
+
variantInstance.x = 240
|
|
287
|
+
variantInstance.y = 40
|
|
288
|
+
figma.currentPage.appendChild(variantInstance)
|
|
289
|
+
|
|
290
|
+
figma.closePlugin(JSON.stringify({
|
|
291
|
+
componentId: comp.id,
|
|
292
|
+
componentSetId: compSet.id,
|
|
293
|
+
placedInstanceIds: [instance.id, variantInstance.id]
|
|
294
|
+
}))
|
|
295
|
+
} catch (e) {
|
|
296
|
+
figma.closePluginWithFailure(e.toString())
|
|
297
|
+
}
|
|
298
|
+
})()
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Component Set with Variable Modes (Full Pattern)
|
|
302
|
+
|
|
303
|
+
```js
|
|
304
|
+
(async () => {
|
|
305
|
+
try {
|
|
306
|
+
await figma.loadFontAsync({ family: "Inter", style: "Medium" })
|
|
307
|
+
|
|
308
|
+
// 1. Create color collection with modes per variant
|
|
309
|
+
const colors = figma.variables.createVariableCollection("Component/Colors")
|
|
310
|
+
colors.renameMode(colors.modes[0].modeId, "primary")
|
|
311
|
+
const primaryMode = colors.modes[0].modeId
|
|
312
|
+
const secondaryMode = colors.addMode("secondary")
|
|
313
|
+
|
|
314
|
+
const bgVar = figma.variables.createVariable("bg", colors, "COLOR")
|
|
315
|
+
bgVar.setValueForMode(primaryMode, { r: 0, g: 0.4, b: 0.9, a: 1 })
|
|
316
|
+
bgVar.setValueForMode(secondaryMode, { r: 0, g: 0, b: 0, a: 0 })
|
|
317
|
+
|
|
318
|
+
const textVar = figma.variables.createVariable("text-color", colors, "COLOR")
|
|
319
|
+
textVar.setValueForMode(primaryMode, { r: 1, g: 1, b: 1, a: 1 })
|
|
320
|
+
textVar.setValueForMode(secondaryMode, { r: 0.1, g: 0.1, b: 0.1, a: 1 })
|
|
321
|
+
|
|
322
|
+
// 2. Create components with variable bindings
|
|
323
|
+
const modeMap = { primary: primaryMode, secondary: secondaryMode }
|
|
324
|
+
const components = []
|
|
325
|
+
|
|
326
|
+
for (const [variantName, modeId] of Object.entries(modeMap)) {
|
|
327
|
+
const comp = figma.createComponent()
|
|
328
|
+
comp.name = "variant=" + variantName
|
|
329
|
+
comp.layoutMode = "HORIZONTAL"
|
|
330
|
+
comp.primaryAxisAlignItems = "CENTER"
|
|
331
|
+
comp.counterAxisAlignItems = "CENTER"
|
|
332
|
+
comp.paddingLeft = 12; comp.paddingRight = 12
|
|
333
|
+
comp.layoutSizingHorizontal = "HUG"
|
|
334
|
+
comp.layoutSizingVertical = "HUG"
|
|
335
|
+
comp.cornerRadius = 6
|
|
336
|
+
|
|
337
|
+
// Bind background fill to variable
|
|
338
|
+
const bgPaint = figma.variables.setBoundVariableForPaint(
|
|
339
|
+
{ type: "SOLID", color: { r: 0, g: 0, b: 0 } }, "color", bgVar
|
|
340
|
+
)
|
|
341
|
+
comp.fills = [bgPaint]
|
|
342
|
+
|
|
343
|
+
// Add text with bound color
|
|
344
|
+
const label = figma.createText()
|
|
345
|
+
label.fontName = { family: "Inter", style: "Medium" }
|
|
346
|
+
label.characters = "Button"
|
|
347
|
+
label.fontSize = 14
|
|
348
|
+
const textPaint = figma.variables.setBoundVariableForPaint(
|
|
349
|
+
{ type: "SOLID", color: { r: 0, g: 0, b: 0 } }, "color", textVar
|
|
350
|
+
)
|
|
351
|
+
label.fills = [textPaint]
|
|
352
|
+
comp.appendChild(label)
|
|
353
|
+
|
|
354
|
+
// 3. CRITICAL: Set explicit mode so this variant renders correctly
|
|
355
|
+
comp.setExplicitVariableModeForCollection(colors.id, modeId)
|
|
356
|
+
|
|
357
|
+
components.push(comp)
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// 4. Combine into component set
|
|
361
|
+
const componentSet = figma.combineAsVariants(components, figma.currentPage)
|
|
362
|
+
componentSet.name = "Button"
|
|
363
|
+
|
|
364
|
+
figma.closePlugin(JSON.stringify({
|
|
365
|
+
componentSetId: componentSet.id,
|
|
366
|
+
colorCollectionId: colors.id
|
|
367
|
+
}))
|
|
368
|
+
} catch (e) {
|
|
369
|
+
figma.closePluginWithFailure(e.toString())
|
|
370
|
+
}
|
|
371
|
+
})()
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Large ComponentSet with Variable Modes (Multi-Step Pattern)
|
|
375
|
+
|
|
376
|
+
For component sets with many variants (50+), split into multiple `use_figma` calls:
|
|
377
|
+
|
|
378
|
+
**Call 1: Create variable collections and return IDs**
|
|
379
|
+
|
|
380
|
+
```js
|
|
381
|
+
(async () => {
|
|
382
|
+
try {
|
|
383
|
+
// Hex-to-0-1 helper
|
|
384
|
+
const hex = (h) => {
|
|
385
|
+
if (!h) return { r: 0, g: 0, b: 0, a: 0 }; // transparent
|
|
386
|
+
return {
|
|
387
|
+
r: parseInt(h.slice(1,3), 16) / 255,
|
|
388
|
+
g: parseInt(h.slice(3,5), 16) / 255,
|
|
389
|
+
b: parseInt(h.slice(5,7), 16) / 255,
|
|
390
|
+
a: 1
|
|
391
|
+
};
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
const coll = figma.variables.createVariableCollection("MyComponent/Colors");
|
|
395
|
+
coll.renameMode(coll.modes[0].modeId, "mode1");
|
|
396
|
+
const mode2Id = coll.addMode("mode2");
|
|
397
|
+
|
|
398
|
+
// Create variables from data map
|
|
399
|
+
const colorData = { "bg/default": ["#0B6BCB", "#636B74"], /* ... */ };
|
|
400
|
+
const modeOrder = ["mode1", "mode2"];
|
|
401
|
+
const modeIds = { mode1: coll.modes[0].modeId, mode2: mode2Id };
|
|
402
|
+
const varIds = {};
|
|
403
|
+
|
|
404
|
+
for (const [name, values] of Object.entries(colorData)) {
|
|
405
|
+
const v = figma.variables.createVariable(name, coll, "COLOR");
|
|
406
|
+
values.forEach((hex_val, i) => {
|
|
407
|
+
v.setValueForMode(modeIds[modeOrder[i]], hex_val ? hex(hex_val) : { r:0, g:0, b:0, a:0 });
|
|
408
|
+
});
|
|
409
|
+
varIds[name] = v.id;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Return ALL IDs — needed by subsequent calls
|
|
413
|
+
figma.closePlugin(JSON.stringify({ collId: coll.id, modeIds, varIds }));
|
|
414
|
+
} catch (e) {
|
|
415
|
+
figma.closePluginWithFailure(e.toString());
|
|
416
|
+
}
|
|
417
|
+
})()
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**Call 2: Create components using stored IDs, combine and layout**
|
|
421
|
+
|
|
422
|
+
```js
|
|
423
|
+
(async () => {
|
|
424
|
+
try {
|
|
425
|
+
await figma.loadFontAsync({ family: "Inter", style: "Semi Bold" });
|
|
426
|
+
|
|
427
|
+
// Paste IDs from Call 1 as literals
|
|
428
|
+
const collId = "VariableCollectionId:X:Y";
|
|
429
|
+
const modeIds = { mode1: "X:0", mode2: "X:1" };
|
|
430
|
+
const varIds = { /* ... from Call 1 ... */ };
|
|
431
|
+
|
|
432
|
+
const getVar = (id) => figma.variables.getVariableById(id);
|
|
433
|
+
const bindColor = (varId) => figma.variables.setBoundVariableForPaint(
|
|
434
|
+
{ type: 'SOLID', color: { r: 0, g: 0, b: 0 } }, 'color', getVar(varId)
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
const components = [];
|
|
438
|
+
for (const mode of ["mode1", "mode2"]) {
|
|
439
|
+
for (const state of ["default", "hover"]) {
|
|
440
|
+
const comp = figma.createComponent();
|
|
441
|
+
comp.name = `mode=${mode}, state=${state}`;
|
|
442
|
+
comp.layoutMode = 'HORIZONTAL';
|
|
443
|
+
comp.primaryAxisAlignItems = 'CENTER';
|
|
444
|
+
comp.counterAxisAlignItems = 'CENTER';
|
|
445
|
+
comp.layoutSizingHorizontal = 'HUG';
|
|
446
|
+
comp.layoutSizingVertical = 'HUG';
|
|
447
|
+
comp.fills = [bindColor(varIds[`bg/${state}`])];
|
|
448
|
+
comp.setExplicitVariableModeForCollection(collId, modeIds[mode]);
|
|
449
|
+
// ... add text children ...
|
|
450
|
+
components.push(comp);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Combine — all children stack at (0,0)!
|
|
455
|
+
const cs = figma.combineAsVariants(components, figma.currentPage);
|
|
456
|
+
cs.name = "MyComponent";
|
|
457
|
+
|
|
458
|
+
// CRITICAL: layout variants in a structured grid mapped to variant axes.
|
|
459
|
+
const stateOrder = ["default", "hover"];
|
|
460
|
+
const modeOrder2 = ["mode1", "mode2"];
|
|
461
|
+
const colW = 140, rowH = 56;
|
|
462
|
+
|
|
463
|
+
for (const child of cs.children) {
|
|
464
|
+
const props = Object.fromEntries(
|
|
465
|
+
child.name.split(', ').map(p => p.split('='))
|
|
466
|
+
);
|
|
467
|
+
const col = stateOrder.indexOf(props.state);
|
|
468
|
+
const row = modeOrder2.indexOf(props.mode);
|
|
469
|
+
child.x = col * colW;
|
|
470
|
+
child.y = row * rowH;
|
|
471
|
+
}
|
|
472
|
+
// Resize from actual child bounds
|
|
473
|
+
let maxX = 0, maxY = 0;
|
|
474
|
+
for (const child of cs.children) {
|
|
475
|
+
maxX = Math.max(maxX, child.x + child.width);
|
|
476
|
+
maxY = Math.max(maxY, child.y + child.height);
|
|
477
|
+
}
|
|
478
|
+
cs.resizeWithoutConstraints(maxX + 40, maxY + 40);
|
|
479
|
+
|
|
480
|
+
// Wrap in section
|
|
481
|
+
const section = figma.createSection();
|
|
482
|
+
section.name = "MyComponent Section";
|
|
483
|
+
section.appendChild(cs);
|
|
484
|
+
section.resizeWithoutConstraints(cs.width + 200, cs.height + 200);
|
|
485
|
+
|
|
486
|
+
figma.closePlugin(JSON.stringify({ csId: cs.id, count: components.length }));
|
|
487
|
+
} catch (e) {
|
|
488
|
+
figma.closePluginWithFailure(e.toString());
|
|
489
|
+
}
|
|
490
|
+
})()
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
## Read Existing Nodes and Return Data
|
|
494
|
+
|
|
495
|
+
```js
|
|
496
|
+
(async () => {
|
|
497
|
+
try {
|
|
498
|
+
const page = figma.currentPage
|
|
499
|
+
const nodes = page.findAll(n => n.type === 'FRAME')
|
|
500
|
+
const data = nodes.map(n => ({
|
|
501
|
+
id: n.id,
|
|
502
|
+
name: n.name,
|
|
503
|
+
width: n.width,
|
|
504
|
+
height: n.height,
|
|
505
|
+
childCount: n.children?.length || 0
|
|
506
|
+
}))
|
|
507
|
+
figma.closePlugin(JSON.stringify({ frames: data }))
|
|
508
|
+
} catch (e) {
|
|
509
|
+
figma.closePluginWithFailure(e.toString())
|
|
510
|
+
}
|
|
511
|
+
})()
|
|
512
|
+
```
|