@sarjallab09/figma-intelligence 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.
- package/LICENSE +26 -0
- package/README.md +327 -0
- package/bin/cli.js +859 -0
- package/design-bridge/.env.example +5 -0
- package/design-bridge/bridge.js +196 -0
- package/design-bridge/lib/assets.js +367 -0
- package/design-bridge/lib/prompt.js +85 -0
- package/design-bridge/lib/server.js +66 -0
- package/design-bridge/lib/stitch.js +37 -0
- package/design-bridge/lib/tokens.js +82 -0
- package/design-bridge/package-lock.json +579 -0
- package/design-bridge/package.json +19 -0
- package/figma-bridge-plugin/README.md +97 -0
- package/figma-bridge-plugin/anthropic-chat-runner.js +192 -0
- package/figma-bridge-plugin/bridge-relay.js +2363 -0
- package/figma-bridge-plugin/chat-runner.js +459 -0
- package/figma-bridge-plugin/code.js +1528 -0
- package/figma-bridge-plugin/codex-runner.js +505 -0
- package/figma-bridge-plugin/component-schemas.js +110 -0
- package/figma-bridge-plugin/content-context.js +869 -0
- package/figma-bridge-plugin/create-button.js +216 -0
- package/figma-bridge-plugin/gemini-cli-runner.js +291 -0
- package/figma-bridge-plugin/gemini-runner.js +187 -0
- package/figma-bridge-plugin/html-to-figma.js +927 -0
- package/figma-bridge-plugin/knowledge-hub/.gitkeep +0 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/anatomy-spec.md +159 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/api-spec.md +162 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/color-spec.md +148 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/full-spec-template.md +314 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/property-spec.md +175 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/screen-reader-spec.md +180 -0
- package/figma-bridge-plugin/knowledge-hub/uspec-references/structure-spec.md +165 -0
- package/figma-bridge-plugin/manifest.json +21 -0
- package/figma-bridge-plugin/package-lock.json +1936 -0
- package/figma-bridge-plugin/package.json +20 -0
- package/figma-bridge-plugin/perplexity-runner.js +188 -0
- package/figma-bridge-plugin/references/SKILL.md +178 -0
- package/figma-bridge-plugin/references/anatomy-spec.md +159 -0
- package/figma-bridge-plugin/references/api-spec.md +162 -0
- package/figma-bridge-plugin/references/color-spec.md +148 -0
- package/figma-bridge-plugin/references/full-spec-template.md +314 -0
- package/figma-bridge-plugin/references/property-spec.md +175 -0
- package/figma-bridge-plugin/references/screen-reader-spec.md +180 -0
- package/figma-bridge-plugin/references/structure-spec.md +165 -0
- package/figma-bridge-plugin/shared-prompt-config.js +604 -0
- package/figma-bridge-plugin/spec-helpers/build-table.js +269 -0
- package/figma-bridge-plugin/spec-helpers/classify-elements.js +189 -0
- package/figma-bridge-plugin/spec-helpers/index.js +35 -0
- package/figma-bridge-plugin/spec-helpers/parse-figma-link.js +49 -0
- package/figma-bridge-plugin/spec-helpers/position-markers.js +158 -0
- package/figma-bridge-plugin/stitch-auth.js +322 -0
- package/figma-bridge-plugin/stitch-runner.js +1427 -0
- package/figma-bridge-plugin/token-resolver.js +107 -0
- package/figma-bridge-plugin/ui.html +4467 -0
- package/figma-intelligence-layer/.env.example +39 -0
- package/figma-intelligence-layer/docs/local-image-generation.md +60 -0
- package/figma-intelligence-layer/examples/comfyui-workflow-template.example.json +101 -0
- package/figma-intelligence-layer/jest.config.js +14 -0
- package/figma-intelligence-layer/mcp-config.json +19 -0
- package/figma-intelligence-layer/package-lock.json +5892 -0
- package/figma-intelligence-layer/package.json +48 -0
- package/figma-intelligence-layer/scripts/setup-comfyui-local.sh +67 -0
- package/figma-intelligence-layer/scripts/start-comfyui.sh +33 -0
- package/figma-intelligence-layer/src/index.ts +2233 -0
- package/figma-intelligence-layer/src/shared/auto-layout-validator.ts +404 -0
- package/figma-intelligence-layer/src/shared/cache.ts +187 -0
- package/figma-intelligence-layer/src/shared/color-operations.ts +533 -0
- package/figma-intelligence-layer/src/shared/color-utils.ts +138 -0
- package/figma-intelligence-layer/src/shared/component-script-builder.ts +413 -0
- package/figma-intelligence-layer/src/shared/component-templates.ts +2767 -0
- package/figma-intelligence-layer/src/shared/concept-taxonomy.ts +694 -0
- package/figma-intelligence-layer/src/shared/decision-log.ts +128 -0
- package/figma-intelligence-layer/src/shared/design-system-context.ts +568 -0
- package/figma-intelligence-layer/src/shared/design-system-intelligence.ts +131 -0
- package/figma-intelligence-layer/src/shared/design-system-matcher.ts +184 -0
- package/figma-intelligence-layer/src/shared/design-system-normalizers.ts +196 -0
- package/figma-intelligence-layer/src/shared/design-system-tokens.ts +295 -0
- package/figma-intelligence-layer/src/shared/dtcg-validator.ts +530 -0
- package/figma-intelligence-layer/src/shared/enrichment-pipeline.ts +671 -0
- package/figma-intelligence-layer/src/shared/figma-bridge.ts +1408 -0
- package/figma-intelligence-layer/src/shared/font-config.ts +126 -0
- package/figma-intelligence-layer/src/shared/icon-catalog.ts +360 -0
- package/figma-intelligence-layer/src/shared/icon-fetch.ts +80 -0
- package/figma-intelligence-layer/src/shared/prototype-script-builder.ts +162 -0
- package/figma-intelligence-layer/src/shared/response-compression.ts +440 -0
- package/figma-intelligence-layer/src/shared/semantic-token-catalog.ts +324 -0
- package/figma-intelligence-layer/src/shared/token-binder.ts +505 -0
- package/figma-intelligence-layer/src/shared/token-math.ts +427 -0
- package/figma-intelligence-layer/src/shared/token-naming.ts +468 -0
- package/figma-intelligence-layer/src/shared/token-utils.ts +420 -0
- package/figma-intelligence-layer/src/shared/types.ts +346 -0
- package/figma-intelligence-layer/src/shared/typography-presets.ts +94 -0
- package/figma-intelligence-layer/src/shared/unsplash.ts +165 -0
- package/figma-intelligence-layer/src/shared/vision-client.ts +607 -0
- package/figma-intelligence-layer/src/shared/vision-provider-anthropic.ts +334 -0
- package/figma-intelligence-layer/src/shared/vision-provider-openai.ts +446 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-handler.ts +782 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-renderer.ts +496 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotation-kit.ts +230 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/colorblind-sim.ts +66 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/index.ts +810 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-analyzer.ts +1191 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-figma-page.ts +1346 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-handler.ts +148 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-figma-page.ts +499 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-report.ts +910 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-checker.ts +989 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-criteria.ts +1160 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/design-from-ref/index.ts +424 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/component-recognizer.ts +38 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/ds-matcher.ts +111 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/font-matcher.ts +114 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/icon-resolver.ts +103 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/index.ts +1060 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/layout-segmenter.ts +18 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/token-inferencer.ts +39 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/vision-pipeline.ts +58 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/sketch-to-design/index.ts +298 -0
- package/figma-intelligence-layer/src/tools/phase1-vision/visual-audit/index.ts +197 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/component-audit/index.ts +494 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/intent-translator/index.ts +356 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/container-patterns.ts +123 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/index.ts +663 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/built-in-rules.yaml +56 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/index.ts +614 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/rule-engine.ts +113 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/color-theory.ts +178 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/index.ts +470 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/index.ts +429 -0
- package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/token-override-maps.ts +226 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/ai-image-insert/index.ts +535 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/index.ts +660 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/pattern-fingerprints.ts +209 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/composition-builder/index.ts +540 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/figma-animated-build.ts +391 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/index.ts +2019 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/screen-templates.ts +131 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/prototype-map/index.ts +381 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/prototype-wire/index.ts +565 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/swarm-build/index.ts +764 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/system-drift/index.ts +535 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/unsplash-search/index.ts +84 -0
- package/figma-intelligence-layer/src/tools/phase3-generation/url-to-frame/index.ts +401 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/css-animations.ts +68 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/framer-motion.ts +78 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/swift-animations.ts +93 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/index.ts +596 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/ci-check/index.ts +462 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/export-tokens/index.ts +1470 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/generate-component-code/index.ts +829 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/handoff-spec/index.ts +702 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/icon-library-sync/index.ts +483 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/index.ts +501 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/storybook-parser.ts +106 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/watch-docs/index.ts +676 -0
- package/figma-intelligence-layer/src/tools/phase4-sync/webhook-listener/index.ts +560 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/apg-doc/index.ts +1043 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/component-detection.ts +620 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/anatomy.ts +331 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/color-tokens.ts +77 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/properties.ts +54 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/snapshot.ts +287 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/spacing.ts +71 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/states.ts +43 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/typography.ts +71 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/index.ts +221 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/_default.ts +166 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/accordion.ts +232 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/alert.ts +234 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar-group.ts +270 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar.ts +249 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/badge.ts +231 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/banner.ts +293 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/breadcrumb.ts +240 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/button.ts +243 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/calendar.ts +307 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/card.ts +143 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/checkbox.ts +227 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/chip.ts +233 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/combobox.ts +282 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/datepicker.ts +276 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/divider.ts +223 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/drawer.ts +255 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/dropdown-menu.ts +289 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/empty-state.ts +261 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/file-uploader.ts +290 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/form.ts +265 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/grid.ts +238 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/icon.ts +255 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/index.ts +128 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-edit.ts +286 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-message.ts +255 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/input.ts +330 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/link.ts +247 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/list.ts +250 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/menu.ts +247 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/modal.ts +144 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navbar.ts +264 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navigation.ts +251 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/number-input.ts +261 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/pagination.ts +248 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/popover.ts +270 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/progress.ts +251 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/radio.ts +142 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/range-slider.ts +282 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/rating.ts +250 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/search.ts +258 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/segmented-control.ts +265 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/select.ts +319 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/skeleton.ts +256 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/slider.ts +232 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/spinner.ts +239 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/status-dot.ts +252 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/stepper.ts +270 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/table.ts +244 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tabs.ts +143 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tag.ts +243 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/textarea.ts +259 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/time-picker.ts +293 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toast.ts +144 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toggle.ts +289 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toolbar.ts +267 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tooltip.ts +232 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/treeview.ts +257 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/typography.ts +319 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/legacy-compat.ts +121 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/anatomy-diagram.ts +430 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/figma-page.ts +312 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/json.ts +129 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/markdown.ts +78 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/visual-doc.ts +2333 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/accessibility.ts +100 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/anatomy.ts +32 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/color-tokens.ts +59 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/content-guidance.ts +18 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/design-tokens.ts +53 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/interaction-rules.ts +19 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/overview.ts +91 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/properties-api.ts +71 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/qa-criteria.ts +19 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/related-components.ts +110 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/responsive.ts +19 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/size-specs.ts +67 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/spacing-structure.ts +58 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/state-specs.ts +79 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/states.ts +50 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/type-hierarchy.ts +33 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/typography.ts +55 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/usage-guidelines.ts +73 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/variants.ts +81 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/types.ts +409 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/index.ts +198 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/renderer.ts +701 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/types.ts +88 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/decision-log/index.ts +135 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/design-decision-log/index.ts +491 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-primitives/index.ts +416 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-scaffolder/index.ts +722 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/ds-variables/index.ts +449 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/health-report/index.ts +393 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/index.ts +406 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/figma-page.ts +292 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/json.ts +24 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/markdown.ts +172 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/naming-guide.ts +409 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/token-analytics/index.ts +594 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/token-docs/index.ts +710 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/token-migrate/index.ts +458 -0
- package/figma-intelligence-layer/src/tools/phase5-governance/token-naming/index.ts +134 -0
- package/figma-intelligence-layer/tests/apg-doc.test.ts +101 -0
- package/figma-intelligence-layer/tests/design-system-context.test.ts +152 -0
- package/figma-intelligence-layer/tests/design-system-matcher.test.ts +144 -0
- package/figma-intelligence-layer/tests/figma-bridge.test.ts +83 -0
- package/figma-intelligence-layer/tests/generate-image-and-insert.test.ts +56 -0
- package/figma-intelligence-layer/tests/screen-cloner-regression.test.ts +69 -0
- package/figma-intelligence-layer/tests/smoke.test.ts +174 -0
- package/figma-intelligence-layer/tests/spec-generator.test.ts +127 -0
- package/figma-intelligence-layer/tests/token-migrate.test.ts +21 -0
- package/figma-intelligence-layer/tests/token-naming.test.ts +30 -0
- package/figma-intelligence-layer/tsconfig.json +19 -0
- package/package.json +35 -0
- package/scripts/clean-existing-chunks.js +179 -0
- package/scripts/connect-ai-tool.js +490 -0
- package/scripts/convert-hub-pdfs.js +425 -0
- package/scripts/figma-mcp-status.js +349 -0
- package/scripts/register-codex-mcp.js +96 -0
|
@@ -0,0 +1,701 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* component-spec-sheet/renderer.ts
|
|
3
|
+
*
|
|
4
|
+
* Builds a single Figma Plugin API script that creates an EightShapes-Specs-style
|
|
5
|
+
* visual spec sheet directly on canvas.
|
|
6
|
+
*
|
|
7
|
+
* Key visual output (matching the reference):
|
|
8
|
+
* ┌───────────────────────────────────────────┐
|
|
9
|
+
* │ Type=Primary, Size=sm, State=Default │ ← header: variant string only
|
|
10
|
+
* │ │
|
|
11
|
+
* │ Anatomy │
|
|
12
|
+
* │ ┌─ gray card ──────────────────────────┐ │
|
|
13
|
+
* │ │ [component] ① ② │ ① leadingIcon │ │ ← numbered colored dots on
|
|
14
|
+
* │ │ │ ② Label │ │ the component + legend
|
|
15
|
+
* │ │ │ ③ trailingIcon │ │
|
|
16
|
+
* │ └─────────────────────────────────────┘ │
|
|
17
|
+
* │ │
|
|
18
|
+
* │ Properties │
|
|
19
|
+
* │ Type │
|
|
20
|
+
* │ ┌─ gray row ──────────────────────────┐ │
|
|
21
|
+
* │ │ [instance] │ Primary │ │ ← each value = own row
|
|
22
|
+
* │ │ │ • Button │ │ with deep style extraction
|
|
23
|
+
* │ │ │ • fill: #2563EB │ │
|
|
24
|
+
* │ │ │ • font: Inter 14 │ │
|
|
25
|
+
* │ │ │ • size: 120 × 40 │ │
|
|
26
|
+
* │ └─────────────────────────────────────┘ │
|
|
27
|
+
* │ ┌─ gray row ──────────────────────────┐ │
|
|
28
|
+
* │ │ [instance] │ Secondary │ │
|
|
29
|
+
* │ │ │ • Button ... │ │
|
|
30
|
+
* │ └─────────────────────────────────────┘ │
|
|
31
|
+
* │ ... │
|
|
32
|
+
* │ │
|
|
33
|
+
* │ Layout and spacing │
|
|
34
|
+
* │ Selected node │
|
|
35
|
+
* │ ┌─ gray card ──────────────────────────┐ │
|
|
36
|
+
* │ │ [component] │ • Button │ │
|
|
37
|
+
* │ │ ██ overlay │ • layoutMode: H │ │ ← colored padding/gap
|
|
38
|
+
* │ │ │ • padding: 8,16,8,16 │ │ overlays + property dump
|
|
39
|
+
* │ └─────────────────────────────────────┘ │
|
|
40
|
+
* └───────────────────────────────────────────┘
|
|
41
|
+
*
|
|
42
|
+
* IMPORTANT Figma pattern: layoutSizingHorizontal = "FILL" only works
|
|
43
|
+
* AFTER the node is appended to an auto-layout parent.
|
|
44
|
+
*/
|
|
45
|
+
import type { SpecSheetPlan } from "./types.js";
|
|
46
|
+
|
|
47
|
+
// ── Design tokens ────────────────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
const PAGE_W = 960;
|
|
50
|
+
const PAD = 40;
|
|
51
|
+
|
|
52
|
+
const C = {
|
|
53
|
+
textMain: "{ r: 0.067, g: 0.094, b: 0.153 }", // #111827
|
|
54
|
+
textMuted: "{ r: 0.42, g: 0.45, b: 0.49 }", // #6b7280
|
|
55
|
+
textLabel: "{ r: 0.294, g: 0.333, b: 0.388 }", // #4b5563
|
|
56
|
+
bgCard: "{ r: 0.965, g: 0.968, b: 0.973 }", // #f6f7f8
|
|
57
|
+
border: "{ r: 0.898, g: 0.906, b: 0.922 }", // #e5e7eb
|
|
58
|
+
white: "{ r: 1, g: 1, b: 1 }",
|
|
59
|
+
markerRed: "{ r: 0.85, g: 0.24, b: 0.24 }", // #d93d3d (like the ref)
|
|
60
|
+
padGreen: "{ r: 0.18, g: 0.72, b: 0.33 }", // #2eb854
|
|
61
|
+
gapBlue: "{ r: 0.26, g: 0.52, b: 0.96 }", // #4285f5
|
|
62
|
+
elemBlue: "{ r: 0.73, g: 0.85, b: 0.98 }", // #bad9fa
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function esc(s: string): string { return JSON.stringify(s); }
|
|
66
|
+
|
|
67
|
+
// ── Font loader ─────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
const FL = `
|
|
70
|
+
var F={};
|
|
71
|
+
async function lf(k,a){for(var i=0;i<a.length;i++){try{await figma.loadFontAsync(a[i]);F[k]=a[i];return}catch(e){}}F[k]={family:"Arial",style:"Regular"};try{await figma.loadFontAsync(F[k])}catch(e){}}
|
|
72
|
+
await lf("b",[{family:"Inter",style:"Bold"},{family:"Roboto",style:"Bold"}]);
|
|
73
|
+
await lf("sb",[{family:"Inter",style:"SemiBold"},{family:"Inter",style:"Medium"},{family:"Roboto",style:"Medium"}]);
|
|
74
|
+
await lf("r",[{family:"Inter",style:"Regular"},{family:"Roboto",style:"Regular"}]);
|
|
75
|
+
await lf("mono",[{family:"SF Mono",style:"Regular"},{family:"Roboto Mono",style:"Regular"},{family:"Courier New",style:"Regular"}]);
|
|
76
|
+
`;
|
|
77
|
+
|
|
78
|
+
// ── Micro JS helpers ────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
function spacerJS(h: number, parent = "m"): string {
|
|
81
|
+
return `(function(){var sp=figma.createFrame();sp.resize(4,${h});sp.fills=[];${parent}.appendChild(sp);sp.layoutSizingHorizontal="FILL";})();`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function dividerJS(parent = "m"): string {
|
|
85
|
+
return `(function(){var dv=figma.createRectangle();dv.resize(4,1);dv.fills=[{type:"SOLID",color:${C.border}}];${parent}.appendChild(dv);dv.layoutSizingHorizontal="FILL";})();`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// ── Deep style extractor (runs inside execute) ──────────────────────────
|
|
89
|
+
// This function is injected into the Figma script once, then called
|
|
90
|
+
// for every variant instance to pull out fill colors, typography,
|
|
91
|
+
// padding, and corner-radius from the instance AND its children.
|
|
92
|
+
|
|
93
|
+
const EXTRACT_STYLE_FN = `
|
|
94
|
+
function extractStyle(node){
|
|
95
|
+
var info={fills:[],texts:[],padding:null,radius:null,w:Math.round(node.width),h:Math.round(node.height)};
|
|
96
|
+
// Root fills
|
|
97
|
+
if(Array.isArray(node.fills)){
|
|
98
|
+
for(var fi=0;fi<node.fills.length;fi++){
|
|
99
|
+
var p=node.fills[fi];
|
|
100
|
+
if(p.type==="SOLID"&&p.visible!==false&&p.color){
|
|
101
|
+
var r=Math.round(p.color.r*255),g=Math.round(p.color.g*255),b=Math.round(p.color.b*255);
|
|
102
|
+
info.fills.push("#"+[r,g,b].map(function(v){return v.toString(16).padStart(2,"0")}).join(""));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Radius
|
|
107
|
+
if(typeof node.cornerRadius==="number"&&node.cornerRadius>0)info.radius=node.cornerRadius;
|
|
108
|
+
// Padding
|
|
109
|
+
if("paddingTop" in node){
|
|
110
|
+
var pt=node.paddingTop||0,pr=node.paddingRight||0,pb=node.paddingBottom||0,pl=node.paddingLeft||0;
|
|
111
|
+
if(pt+pr+pb+pl>0)info.padding=pt+", "+pr+", "+pb+", "+pl;
|
|
112
|
+
}
|
|
113
|
+
// BFS for text + child fills
|
|
114
|
+
var q=("children" in node)?node.children.slice(0,12):[];
|
|
115
|
+
var depth=0;
|
|
116
|
+
while(q.length>0&&depth<3){
|
|
117
|
+
var next=[];depth++;
|
|
118
|
+
for(var qi=0;qi<q.length;qi++){
|
|
119
|
+
var c=q[qi];
|
|
120
|
+
if(c.type==="TEXT"){
|
|
121
|
+
var fn=c.fontName;
|
|
122
|
+
var family=(fn&&fn!==figma.mixed)?fn.family:"Mixed";
|
|
123
|
+
var style=(fn&&fn!==figma.mixed)?fn.style:"";
|
|
124
|
+
var fs=(typeof c.fontSize==="number")?c.fontSize:0;
|
|
125
|
+
info.texts.push(family+" "+style+" "+fs);
|
|
126
|
+
}
|
|
127
|
+
if(Array.isArray(c.fills)){
|
|
128
|
+
for(var cfi=0;cfi<c.fills.length;cfi++){
|
|
129
|
+
var cp=c.fills[cfi];
|
|
130
|
+
if(cp.type==="SOLID"&&cp.visible!==false&&cp.color){
|
|
131
|
+
var cr=Math.round(cp.color.r*255),cg=Math.round(cp.color.g*255),cb=Math.round(cp.color.b*255);
|
|
132
|
+
var hex="#"+[cr,cg,cb].map(function(v){return v.toString(16).padStart(2,"0")}).join("");
|
|
133
|
+
if(info.fills.indexOf(hex)===-1)info.fills.push(hex);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if("children" in c&&c.children)for(var sci=0;sci<Math.min(c.children.length,8);sci++)next.push(c.children[sci]);
|
|
138
|
+
}
|
|
139
|
+
q=next;
|
|
140
|
+
}
|
|
141
|
+
// Deduplicate texts
|
|
142
|
+
var seen={};info.texts=info.texts.filter(function(t){if(seen[t])return false;seen[t]=true;return true;});
|
|
143
|
+
return info;
|
|
144
|
+
}
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
// ── Build: header ───────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
function buildHeaderJS(plan: SpecSheetPlan): string {
|
|
150
|
+
// Exactly like the reference: just the variant property string, centered, bold
|
|
151
|
+
const label = plan.variantLabel || plan.componentName;
|
|
152
|
+
return `
|
|
153
|
+
// ── HEADER ──
|
|
154
|
+
(function(){
|
|
155
|
+
var ht=figma.createText();ht.fontName=F.b;ht.fontSize=24;
|
|
156
|
+
ht.lineHeight={unit:"PIXELS",value:32};
|
|
157
|
+
ht.characters=${esc(label)};
|
|
158
|
+
ht.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
159
|
+
ht.textAutoResize="HEIGHT";
|
|
160
|
+
ht.textAlignHorizontal="CENTER";
|
|
161
|
+
m.appendChild(ht);ht.layoutSizingHorizontal="FILL";
|
|
162
|
+
})();
|
|
163
|
+
${spacerJS(32)}
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ── Build: anatomy ──────────────────────────────────────────────────────
|
|
168
|
+
|
|
169
|
+
function buildAnatomyJS(plan: SpecSheetPlan): string {
|
|
170
|
+
if (plan.markers.length === 0) return "";
|
|
171
|
+
|
|
172
|
+
const markersJSON = JSON.stringify(plan.markers);
|
|
173
|
+
const MARKER_D = 20;
|
|
174
|
+
const MARKER_MARGIN = 60;
|
|
175
|
+
|
|
176
|
+
return `
|
|
177
|
+
// ── ANATOMY ──
|
|
178
|
+
(function(){
|
|
179
|
+
var secTitle=figma.createText();secTitle.fontName=F.b;secTitle.fontSize=18;
|
|
180
|
+
secTitle.characters="Anatomy";secTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
181
|
+
secTitle.textAutoResize="HEIGHT";m.appendChild(secTitle);secTitle.layoutSizingHorizontal="FILL";
|
|
182
|
+
})();
|
|
183
|
+
${spacerJS(12)}
|
|
184
|
+
(function(){
|
|
185
|
+
// Gray card: component on left, legend on right
|
|
186
|
+
var card=figma.createFrame();card.name="Anatomy";
|
|
187
|
+
card.layoutMode="HORIZONTAL";
|
|
188
|
+
card.primaryAxisSizingMode="AUTO";card.counterAxisSizingMode="AUTO";
|
|
189
|
+
card.paddingTop=32;card.paddingBottom=32;card.paddingLeft=32;card.paddingRight=32;
|
|
190
|
+
card.itemSpacing=40;
|
|
191
|
+
card.fills=[{type:"SOLID",color:${C.bgCard}}];card.cornerRadius=12;
|
|
192
|
+
card.counterAxisAlignItems="CENTER";
|
|
193
|
+
m.appendChild(card);card.layoutSizingHorizontal="FILL";
|
|
194
|
+
|
|
195
|
+
// ── Left: component with external markers + leader lines ──
|
|
196
|
+
var compWrap=figma.createFrame();compWrap.name="Component";
|
|
197
|
+
compWrap.layoutMode="NONE";compWrap.fills=[];
|
|
198
|
+
card.appendChild(compWrap);
|
|
199
|
+
|
|
200
|
+
var src=sourceNode;
|
|
201
|
+
if(src.type==="COMPONENT_SET"&&src.children.length>0)src=src.children[0];
|
|
202
|
+
var clone=src.clone();
|
|
203
|
+
clone.x=${MARKER_MARGIN};clone.y=${MARKER_MARGIN};
|
|
204
|
+
${plan.anatomyScale > 1 ? `clone.rescale(${plan.anatomyScale});` : ""}
|
|
205
|
+
compWrap.appendChild(clone);
|
|
206
|
+
compWrap.resize(clone.width+${MARKER_MARGIN * 2},clone.height+${MARKER_MARGIN * 2});
|
|
207
|
+
|
|
208
|
+
// Place numbered dots OUTSIDE the component with connector lines
|
|
209
|
+
var markers=${markersJSON};
|
|
210
|
+
var MD=${MARKER_D};
|
|
211
|
+
var MR=${MARKER_D / 2};
|
|
212
|
+
for(var i=0;i<markers.length;i++){
|
|
213
|
+
var mk=markers[i];
|
|
214
|
+
|
|
215
|
+
// Connector line from marker to target element
|
|
216
|
+
var connector=figma.createVector();
|
|
217
|
+
var pathData="M "+mk.markerX+" "+mk.markerY+" L "+mk.targetX+" "+mk.targetY;
|
|
218
|
+
connector.vectorPaths=[{windingRule:"NONZERO",data:pathData}];
|
|
219
|
+
connector.strokes=[{type:"SOLID",color:${C.markerRed}}];
|
|
220
|
+
connector.strokeWeight=1.5;connector.fills=[];
|
|
221
|
+
connector.strokeCap="ROUND";connector.opacity=0.7;
|
|
222
|
+
compWrap.appendChild(connector);
|
|
223
|
+
|
|
224
|
+
// Marker dot at edge position (outside component)
|
|
225
|
+
var dot=figma.createEllipse();dot.resize(MD,MD);
|
|
226
|
+
dot.fills=[{type:"SOLID",color:${C.markerRed}}];
|
|
227
|
+
dot.x=mk.markerX-MR;dot.y=mk.markerY-MR;
|
|
228
|
+
dot.name="Marker "+(i+1);
|
|
229
|
+
compWrap.appendChild(dot);
|
|
230
|
+
|
|
231
|
+
var numTxt=figma.createText();numTxt.fontName=F.b;numTxt.fontSize=10;
|
|
232
|
+
numTxt.characters=String(i+1);
|
|
233
|
+
numTxt.fills=[{type:"SOLID",color:{r:1,g:1,b:1}}];
|
|
234
|
+
numTxt.textAutoResize="WIDTH_AND_HEIGHT";
|
|
235
|
+
compWrap.appendChild(numTxt);
|
|
236
|
+
numTxt.x=mk.markerX-numTxt.width/2;
|
|
237
|
+
numTxt.y=mk.markerY-numTxt.height/2;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ── Right: legend list ──
|
|
241
|
+
var legend=figma.createFrame();legend.name="Legend";
|
|
242
|
+
legend.layoutMode="VERTICAL";
|
|
243
|
+
legend.primaryAxisSizingMode="AUTO";legend.counterAxisSizingMode="AUTO";
|
|
244
|
+
legend.itemSpacing=8;legend.fills=[];
|
|
245
|
+
card.appendChild(legend);
|
|
246
|
+
|
|
247
|
+
var roleLabels={"content-element":"Content","optional-slot":"Optional","fixed-sub-component":"Sub-component","structural":"Container","decorative":"Decorative"};
|
|
248
|
+
|
|
249
|
+
for(var j=0;j<markers.length;j++){
|
|
250
|
+
var row=figma.createFrame();row.name="Item "+(j+1);
|
|
251
|
+
row.layoutMode="HORIZONTAL";
|
|
252
|
+
row.primaryAxisSizingMode="AUTO";row.counterAxisSizingMode="AUTO";
|
|
253
|
+
row.itemSpacing=10;row.fills=[];row.counterAxisAlignItems="CENTER";
|
|
254
|
+
legend.appendChild(row);
|
|
255
|
+
|
|
256
|
+
// Numbered dot
|
|
257
|
+
var rDot=figma.createEllipse();rDot.resize(${MARKER_D},${MARKER_D});
|
|
258
|
+
rDot.fills=[{type:"SOLID",color:${C.markerRed}}];
|
|
259
|
+
var rWrap=figma.createFrame();rWrap.name="Num";rWrap.layoutMode="NONE";
|
|
260
|
+
rWrap.resize(${MARKER_D},${MARKER_D});rWrap.fills=[];
|
|
261
|
+
rWrap.appendChild(rDot);rDot.x=0;rDot.y=0;
|
|
262
|
+
var rNum=figma.createText();rNum.fontName=F.b;rNum.fontSize=10;
|
|
263
|
+
rNum.characters=String(j+1);
|
|
264
|
+
rNum.fills=[{type:"SOLID",color:{r:1,g:1,b:1}}];
|
|
265
|
+
rNum.textAutoResize="WIDTH_AND_HEIGHT";
|
|
266
|
+
rWrap.appendChild(rNum);rNum.x=MR-rNum.width/2;rNum.y=MR-rNum.height/2;
|
|
267
|
+
row.appendChild(rWrap);
|
|
268
|
+
|
|
269
|
+
// Element name + role
|
|
270
|
+
var roleTxt=roleLabels[markers[j].role]||markers[j].role;
|
|
271
|
+
var eName=figma.createText();eName.fontName=F.r;eName.fontSize=13;
|
|
272
|
+
eName.lineHeight={unit:"PIXELS",value:20};
|
|
273
|
+
eName.characters=markers[j].name+" \\u2014 "+roleTxt;
|
|
274
|
+
eName.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
275
|
+
eName.textAutoResize="WIDTH_AND_HEIGHT";
|
|
276
|
+
row.appendChild(eName);
|
|
277
|
+
}
|
|
278
|
+
})();
|
|
279
|
+
${spacerJS(32)}
|
|
280
|
+
`;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// ── Build: properties ───────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
function buildPropertiesJS(plan: SpecSheetPlan): string {
|
|
286
|
+
if (plan.propertyAxes.length === 0 && plan.booleanToggles.length === 0) return "";
|
|
287
|
+
|
|
288
|
+
let js = `
|
|
289
|
+
// ── PROPERTIES ──
|
|
290
|
+
(function(){
|
|
291
|
+
var pTitle=figma.createText();pTitle.fontName=F.b;pTitle.fontSize=18;
|
|
292
|
+
pTitle.characters="Properties";pTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
293
|
+
pTitle.textAutoResize="HEIGHT";m.appendChild(pTitle);pTitle.layoutSizingHorizontal="FILL";
|
|
294
|
+
})();
|
|
295
|
+
${spacerJS(8)}
|
|
296
|
+
`;
|
|
297
|
+
|
|
298
|
+
// Each variant axis
|
|
299
|
+
for (const axis of plan.propertyAxes) {
|
|
300
|
+
js += `
|
|
301
|
+
// ── ${axis.axisName} ──
|
|
302
|
+
(function(){
|
|
303
|
+
var axTitle=figma.createText();axTitle.fontName=F.sb;axTitle.fontSize=15;
|
|
304
|
+
axTitle.characters=${esc(axis.axisName)};axTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
305
|
+
axTitle.textAutoResize="HEIGHT";m.appendChild(axTitle);axTitle.layoutSizingHorizontal="FILL";
|
|
306
|
+
})();
|
|
307
|
+
${spacerJS(8)}
|
|
308
|
+
(function(){
|
|
309
|
+
var compSet=sourceNode.type==="COMPONENT_SET"?sourceNode:(sourceNode.parent&&sourceNode.parent.type==="COMPONENT_SET"?sourceNode.parent:null);
|
|
310
|
+
if(!compSet)return;
|
|
311
|
+
var samples=${JSON.stringify(axis.samples)};
|
|
312
|
+
|
|
313
|
+
for(var si=0;si<samples.length;si++){
|
|
314
|
+
var s=samples[si];
|
|
315
|
+
|
|
316
|
+
// Find matching variant
|
|
317
|
+
var target=null;
|
|
318
|
+
for(var ci=0;ci<compSet.children.length;ci++){
|
|
319
|
+
var ch=compSet.children[ci];
|
|
320
|
+
if(!ch.variantProperties)continue;
|
|
321
|
+
var match=true;
|
|
322
|
+
for(var pk in s.props){if(ch.variantProperties[pk]!==s.props[pk]){match=false;break;}}
|
|
323
|
+
if(match){target=ch;break;}
|
|
324
|
+
}
|
|
325
|
+
if(!target&&compSet.children.length>0)target=compSet.children[0];
|
|
326
|
+
if(!target)continue;
|
|
327
|
+
var inst=target.createInstance();
|
|
328
|
+
|
|
329
|
+
// Extract real style data from this instance
|
|
330
|
+
var style=extractStyle(inst);
|
|
331
|
+
|
|
332
|
+
// ── Row card: instance left, metadata right ──
|
|
333
|
+
var row=figma.createFrame();row.name=s.label;
|
|
334
|
+
row.layoutMode="HORIZONTAL";
|
|
335
|
+
row.primaryAxisSizingMode="AUTO";row.counterAxisSizingMode="AUTO";
|
|
336
|
+
row.itemSpacing=40;
|
|
337
|
+
row.paddingTop=24;row.paddingBottom=24;row.paddingLeft=32;row.paddingRight=32;
|
|
338
|
+
row.fills=[{type:"SOLID",color:${C.bgCard}}];row.cornerRadius=8;
|
|
339
|
+
row.counterAxisAlignItems="CENTER";
|
|
340
|
+
m.appendChild(row);row.layoutSizingHorizontal="FILL";
|
|
341
|
+
|
|
342
|
+
// Instance in a fixed-width wrapper for consistent sizing
|
|
343
|
+
var instWrap=figma.createFrame();instWrap.name="Preview";
|
|
344
|
+
instWrap.layoutMode="HORIZONTAL";
|
|
345
|
+
instWrap.primaryAxisSizingMode="FIXED";instWrap.counterAxisSizingMode="AUTO";
|
|
346
|
+
instWrap.resize(160,10);instWrap.fills=[];
|
|
347
|
+
instWrap.primaryAxisAlignItems="CENTER";
|
|
348
|
+
instWrap.counterAxisAlignItems="CENTER";
|
|
349
|
+
row.appendChild(instWrap);
|
|
350
|
+
instWrap.appendChild(inst);
|
|
351
|
+
|
|
352
|
+
// Metadata column
|
|
353
|
+
var meta=figma.createFrame();meta.name="Meta";
|
|
354
|
+
meta.layoutMode="VERTICAL";meta.primaryAxisSizingMode="AUTO";
|
|
355
|
+
meta.counterAxisSizingMode="AUTO";meta.itemSpacing=4;meta.fills=[];
|
|
356
|
+
row.appendChild(meta);
|
|
357
|
+
|
|
358
|
+
// Value name (bold)
|
|
359
|
+
var valName=figma.createText();valName.fontName=F.sb;valName.fontSize=14;
|
|
360
|
+
valName.characters=s.label;valName.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
361
|
+
valName.textAutoResize="WIDTH_AND_HEIGHT";meta.appendChild(valName);
|
|
362
|
+
|
|
363
|
+
// Component name (muted)
|
|
364
|
+
var compName=figma.createText();compName.fontName=F.r;compName.fontSize=12;
|
|
365
|
+
compName.characters="\\u2022 "+${esc(plan.componentName)};
|
|
366
|
+
compName.fills=[{type:"SOLID",color:${C.textMuted}}];
|
|
367
|
+
compName.textAutoResize="WIDTH_AND_HEIGHT";meta.appendChild(compName);
|
|
368
|
+
|
|
369
|
+
// Style details — each on its own line
|
|
370
|
+
var lines=[];
|
|
371
|
+
for(var fi=0;fi<Math.min(style.fills.length,3);fi++){
|
|
372
|
+
lines.push("\\u2022 fill: "+style.fills[fi]);
|
|
373
|
+
}
|
|
374
|
+
for(var ti=0;ti<Math.min(style.texts.length,2);ti++){
|
|
375
|
+
lines.push("\\u2022 font: "+style.texts[ti]);
|
|
376
|
+
}
|
|
377
|
+
lines.push("\\u2022 size: "+style.w+" \\u00D7 "+style.h);
|
|
378
|
+
if(style.radius)lines.push("\\u2022 radius: "+style.radius+"px");
|
|
379
|
+
if(style.padding)lines.push("\\u2022 padding: "+style.padding);
|
|
380
|
+
|
|
381
|
+
if(lines.length>0){
|
|
382
|
+
// Spacer between component name and details
|
|
383
|
+
var detSpacer=figma.createFrame();detSpacer.resize(4,4);detSpacer.fills=[];
|
|
384
|
+
meta.appendChild(detSpacer);detSpacer.layoutSizingHorizontal="FILL";
|
|
385
|
+
|
|
386
|
+
var detTxt=figma.createText();detTxt.fontName=F.r;detTxt.fontSize=11;
|
|
387
|
+
detTxt.lineHeight={unit:"PIXELS",value:18};
|
|
388
|
+
detTxt.characters=lines.join("\\n");
|
|
389
|
+
detTxt.fills=[{type:"SOLID",color:${C.textMuted}}];
|
|
390
|
+
detTxt.textAutoResize="WIDTH_AND_HEIGHT";
|
|
391
|
+
meta.appendChild(detTxt);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
// Row gap spacer between this axis and the next
|
|
395
|
+
})();
|
|
396
|
+
${spacerJS(8)}
|
|
397
|
+
`;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// Boolean toggles
|
|
401
|
+
for (const toggle of plan.booleanToggles) {
|
|
402
|
+
js += `
|
|
403
|
+
// ── ${toggle.name} ──
|
|
404
|
+
(function(){
|
|
405
|
+
var tTitle=figma.createText();tTitle.fontName=F.sb;tTitle.fontSize=15;
|
|
406
|
+
tTitle.characters=${esc(toggle.name)};tTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
407
|
+
tTitle.textAutoResize="HEIGHT";m.appendChild(tTitle);tTitle.layoutSizingHorizontal="FILL";
|
|
408
|
+
})();
|
|
409
|
+
${spacerJS(8)}
|
|
410
|
+
(function(){
|
|
411
|
+
var compSet=sourceNode.type==="COMPONENT_SET"?sourceNode:null;
|
|
412
|
+
if(!compSet||compSet.children.length===0)return;
|
|
413
|
+
var base=compSet.children[0];
|
|
414
|
+
var boolName=${esc(toggle.name)};
|
|
415
|
+
|
|
416
|
+
// Find the component property key (may have #hash suffix)
|
|
417
|
+
var propKey=null;
|
|
418
|
+
if("componentProperties" in compSet&&compSet.componentProperties){
|
|
419
|
+
for(var k in compSet.componentProperties){
|
|
420
|
+
if(k.replace(/#.*$/,"").trim()===boolName){propKey=k;break;}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Create two instance cards (true/false)
|
|
425
|
+
var vals=[true,false];
|
|
426
|
+
for(var vi=0;vi<vals.length;vi++){
|
|
427
|
+
var inst=base.createInstance();
|
|
428
|
+
if(propKey){try{var pp={};pp[propKey]=vals[vi];inst.setProperties(pp);}catch(e){}}
|
|
429
|
+
|
|
430
|
+
var row=figma.createFrame();row.name=boolName+"="+vals[vi];
|
|
431
|
+
row.layoutMode="HORIZONTAL";row.primaryAxisSizingMode="AUTO";
|
|
432
|
+
row.counterAxisSizingMode="AUTO";row.itemSpacing=40;
|
|
433
|
+
row.paddingTop=24;row.paddingBottom=24;row.paddingLeft=32;row.paddingRight=32;
|
|
434
|
+
row.fills=[{type:"SOLID",color:${C.bgCard}}];row.cornerRadius=8;
|
|
435
|
+
row.counterAxisAlignItems="CENTER";
|
|
436
|
+
m.appendChild(row);row.layoutSizingHorizontal="FILL";
|
|
437
|
+
|
|
438
|
+
// Instance in fixed wrapper
|
|
439
|
+
var instWrap=figma.createFrame();instWrap.name="Preview";
|
|
440
|
+
instWrap.layoutMode="HORIZONTAL";
|
|
441
|
+
instWrap.primaryAxisSizingMode="FIXED";instWrap.counterAxisSizingMode="AUTO";
|
|
442
|
+
instWrap.resize(160,10);instWrap.fills=[];
|
|
443
|
+
instWrap.primaryAxisAlignItems="CENTER";
|
|
444
|
+
instWrap.counterAxisAlignItems="CENTER";
|
|
445
|
+
row.appendChild(instWrap);
|
|
446
|
+
instWrap.appendChild(inst);
|
|
447
|
+
|
|
448
|
+
var meta=figma.createFrame();meta.name="Meta";
|
|
449
|
+
meta.layoutMode="VERTICAL";meta.primaryAxisSizingMode="AUTO";
|
|
450
|
+
meta.counterAxisSizingMode="AUTO";meta.itemSpacing=4;meta.fills=[];
|
|
451
|
+
row.appendChild(meta);
|
|
452
|
+
|
|
453
|
+
var vLbl=figma.createText();vLbl.fontName=F.sb;vLbl.fontSize=14;
|
|
454
|
+
vLbl.characters=vals[vi]?"Visible":"Hidden";
|
|
455
|
+
vLbl.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
456
|
+
vLbl.textAutoResize="WIDTH_AND_HEIGHT";meta.appendChild(vLbl);
|
|
457
|
+
|
|
458
|
+
var vSub=figma.createText();vSub.fontName=F.r;vSub.fontSize=12;
|
|
459
|
+
vSub.characters="\\u2022 "+boolName+" = "+vals[vi];
|
|
460
|
+
vSub.fills=[{type:"SOLID",color:${C.textMuted}}];
|
|
461
|
+
vSub.textAutoResize="WIDTH_AND_HEIGHT";meta.appendChild(vSub);
|
|
462
|
+
}
|
|
463
|
+
})();
|
|
464
|
+
${spacerJS(8)}
|
|
465
|
+
`;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
return js;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// ── Build: layout and spacing ───────────────────────────────────────────
|
|
472
|
+
|
|
473
|
+
function buildSpacingJS(plan: SpecSheetPlan): string {
|
|
474
|
+
if (plan.spacingEntries.length === 0) return "";
|
|
475
|
+
|
|
476
|
+
const root = plan.spacingEntries[0];
|
|
477
|
+
const childrenData = JSON.stringify(root.children || []);
|
|
478
|
+
|
|
479
|
+
// Margin around the component for dimension annotations
|
|
480
|
+
const ANNOT_MARGIN = 100;
|
|
481
|
+
const CAP_LEN = 6; // perpendicular end cap length
|
|
482
|
+
const LINE_W = 1.5; // line stroke weight
|
|
483
|
+
|
|
484
|
+
return `
|
|
485
|
+
// ── LAYOUT AND SPACING ──
|
|
486
|
+
${dividerJS()}
|
|
487
|
+
${spacerJS(24)}
|
|
488
|
+
(function(){
|
|
489
|
+
var lsTitle=figma.createText();lsTitle.fontName=F.b;lsTitle.fontSize=18;
|
|
490
|
+
lsTitle.characters="Layout and spacing";lsTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
491
|
+
lsTitle.textAutoResize="HEIGHT";m.appendChild(lsTitle);lsTitle.layoutSizingHorizontal="FILL";
|
|
492
|
+
})();
|
|
493
|
+
${spacerJS(8)}
|
|
494
|
+
(function(){
|
|
495
|
+
var snTitle=figma.createText();snTitle.fontName=F.sb;snTitle.fontSize=14;
|
|
496
|
+
snTitle.characters="Selected node";snTitle.fills=[{type:"SOLID",color:${C.textMain}}];
|
|
497
|
+
snTitle.textAutoResize="HEIGHT";m.appendChild(snTitle);snTitle.layoutSizingHorizontal="FILL";
|
|
498
|
+
})();
|
|
499
|
+
${spacerJS(8)}
|
|
500
|
+
(function(){
|
|
501
|
+
var src=sourceNode;
|
|
502
|
+
if(src.type==="COMPONENT_SET"&&src.children.length>0)src=src.children[0];
|
|
503
|
+
var compClone=src.clone();
|
|
504
|
+
var cW=compClone.width,cH=compClone.height;
|
|
505
|
+
var AM=${ANNOT_MARGIN};
|
|
506
|
+
|
|
507
|
+
// Canvas frame (absolute positioning for dimension markers)
|
|
508
|
+
var canvas=figma.createFrame();canvas.name="Spacing";
|
|
509
|
+
canvas.layoutMode="NONE";
|
|
510
|
+
canvas.fills=[{type:"SOLID",color:${C.bgCard}}];canvas.cornerRadius=12;
|
|
511
|
+
canvas.resize(cW+AM*2,cH+AM*2);
|
|
512
|
+
m.appendChild(canvas);canvas.layoutSizingHorizontal="FILL";
|
|
513
|
+
// Adjust height to fit content
|
|
514
|
+
canvas.resize(Math.max(canvas.width,cW+AM*2),cH+AM*2);
|
|
515
|
+
|
|
516
|
+
// Place the component clone centered in the canvas
|
|
517
|
+
compClone.x=AM;compClone.y=AM;
|
|
518
|
+
canvas.appendChild(compClone);
|
|
519
|
+
|
|
520
|
+
// ── Dimension marker helper ──
|
|
521
|
+
// Draws a line with end caps and a centered label
|
|
522
|
+
function drawDim(parent,x1,y1,x2,y2,label,color){
|
|
523
|
+
var isH=Math.abs(y2-y1)<Math.abs(x2-x1);
|
|
524
|
+
// Main line
|
|
525
|
+
var line=figma.createVector();
|
|
526
|
+
var pth="M "+x1+" "+y1+" L "+x2+" "+y2;
|
|
527
|
+
line.vectorPaths=[{windingRule:"NONZERO",data:pth}];
|
|
528
|
+
line.strokes=[{type:"SOLID",color:color}];
|
|
529
|
+
line.strokeWeight=${LINE_W};line.fills=[];
|
|
530
|
+
line.strokeCap="ROUND";
|
|
531
|
+
parent.appendChild(line);
|
|
532
|
+
|
|
533
|
+
// End caps (perpendicular to main line)
|
|
534
|
+
var capLen=${CAP_LEN};
|
|
535
|
+
if(isH){
|
|
536
|
+
// Vertical end caps
|
|
537
|
+
var c1=figma.createVector();
|
|
538
|
+
c1.vectorPaths=[{windingRule:"NONZERO",data:"M "+x1+" "+(y1-capLen)+" L "+x1+" "+(y1+capLen)}];
|
|
539
|
+
c1.strokes=[{type:"SOLID",color:color}];c1.strokeWeight=${LINE_W};c1.fills=[];
|
|
540
|
+
parent.appendChild(c1);
|
|
541
|
+
var c2=figma.createVector();
|
|
542
|
+
c2.vectorPaths=[{windingRule:"NONZERO",data:"M "+x2+" "+(y2-capLen)+" L "+x2+" "+(y2+capLen)}];
|
|
543
|
+
c2.strokes=[{type:"SOLID",color:color}];c2.strokeWeight=${LINE_W};c2.fills=[];
|
|
544
|
+
parent.appendChild(c2);
|
|
545
|
+
}else{
|
|
546
|
+
// Horizontal end caps
|
|
547
|
+
var c1=figma.createVector();
|
|
548
|
+
c1.vectorPaths=[{windingRule:"NONZERO",data:"M "+(x1-capLen)+" "+y1+" L "+(x1+capLen)+" "+y1}];
|
|
549
|
+
c1.strokes=[{type:"SOLID",color:color}];c1.strokeWeight=${LINE_W};c1.fills=[];
|
|
550
|
+
parent.appendChild(c1);
|
|
551
|
+
var c2=figma.createVector();
|
|
552
|
+
c2.vectorPaths=[{windingRule:"NONZERO",data:"M "+(x2-capLen)+" "+y2+" L "+(x2+capLen)+" "+y2}];
|
|
553
|
+
c2.strokes=[{type:"SOLID",color:color}];c2.strokeWeight=${LINE_W};c2.fills=[];
|
|
554
|
+
parent.appendChild(c2);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Label
|
|
558
|
+
var lbl=figma.createText();lbl.fontName=F.mono;lbl.fontSize=10;
|
|
559
|
+
lbl.characters=label;
|
|
560
|
+
lbl.fills=[{type:"SOLID",color:color}];
|
|
561
|
+
lbl.textAutoResize="WIDTH_AND_HEIGHT";
|
|
562
|
+
parent.appendChild(lbl);
|
|
563
|
+
// Position label at midpoint of line
|
|
564
|
+
var mx=(x1+x2)/2,my=(y1+y2)/2;
|
|
565
|
+
if(isH){
|
|
566
|
+
lbl.x=mx-lbl.width/2;lbl.y=my-lbl.height-4;
|
|
567
|
+
}else{
|
|
568
|
+
lbl.x=mx+4;lbl.y=my-lbl.height/2;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
var padColor=${C.padGreen};
|
|
573
|
+
var gapColor=${C.gapBlue};
|
|
574
|
+
var pt=${root.paddingTop},pr=${root.paddingRight},pb=${root.paddingBottom},pl=${root.paddingLeft};
|
|
575
|
+
var compX=AM,compY=AM;
|
|
576
|
+
|
|
577
|
+
// ── Padding dimension markers ──
|
|
578
|
+
// paddingTop: vertical marker on the right side of component
|
|
579
|
+
if(pt>0){
|
|
580
|
+
var rx=compX+cW+20;
|
|
581
|
+
drawDim(canvas,rx,compY,rx,compY+pt,pt+"px",padColor);
|
|
582
|
+
}
|
|
583
|
+
// paddingBottom: vertical marker on the right side
|
|
584
|
+
if(pb>0){
|
|
585
|
+
var rx=compX+cW+20;
|
|
586
|
+
drawDim(canvas,rx,compY+cH-pb,rx,compY+cH,pb+"px",padColor);
|
|
587
|
+
}
|
|
588
|
+
// paddingLeft: horizontal marker above the component
|
|
589
|
+
if(pl>0){
|
|
590
|
+
var ry=compY-20;
|
|
591
|
+
drawDim(canvas,compX,ry,compX+pl,ry,pl+"px",padColor);
|
|
592
|
+
}
|
|
593
|
+
// paddingRight: horizontal marker above, at right edge
|
|
594
|
+
if(pr>0){
|
|
595
|
+
var ry=compY-20;
|
|
596
|
+
drawDim(canvas,compX+cW-pr,ry,compX+cW,ry,pr+"px",padColor);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// ── Semi-transparent padding overlays on the component ──
|
|
600
|
+
if(pt>0){
|
|
601
|
+
var ot=figma.createRectangle();ot.resize(cW,pt);ot.x=compX;ot.y=compY;
|
|
602
|
+
ot.fills=[{type:"SOLID",color:padColor}];ot.opacity=0.15;canvas.appendChild(ot);
|
|
603
|
+
}
|
|
604
|
+
if(pb>0){
|
|
605
|
+
var ob=figma.createRectangle();ob.resize(cW,pb);ob.x=compX;ob.y=compY+cH-pb;
|
|
606
|
+
ob.fills=[{type:"SOLID",color:padColor}];ob.opacity=0.15;canvas.appendChild(ob);
|
|
607
|
+
}
|
|
608
|
+
if(pl>0){
|
|
609
|
+
var ol=figma.createRectangle();ol.resize(pl,cH);ol.x=compX;ol.y=compY;
|
|
610
|
+
ol.fills=[{type:"SOLID",color:padColor}];ol.opacity=0.15;canvas.appendChild(ol);
|
|
611
|
+
}
|
|
612
|
+
if(pr>0){
|
|
613
|
+
var oR=figma.createRectangle();oR.resize(pr,cH);oR.x=compX+cW-pr;oR.y=compY;
|
|
614
|
+
oR.fills=[{type:"SOLID",color:padColor}];oR.opacity=0.15;canvas.appendChild(oR);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// ── Item spacing markers between children ──
|
|
618
|
+
var children=${childrenData};
|
|
619
|
+
var layoutMode="${root.layoutMode}";
|
|
620
|
+
var itemSpacing=${root.itemSpacing};
|
|
621
|
+
if(children.length>1&&itemSpacing>0){
|
|
622
|
+
for(var ci=0;ci<children.length-1;ci++){
|
|
623
|
+
var c1=children[ci],c2=children[ci+1];
|
|
624
|
+
if(layoutMode==="HORIZONTAL"){
|
|
625
|
+
// Horizontal gap: vertical marker between children
|
|
626
|
+
var gapX1=compX+c1.x+c1.w;
|
|
627
|
+
var gapX2=compX+c2.x;
|
|
628
|
+
var gapY=compY+cH+20;
|
|
629
|
+
drawDim(canvas,gapX1,gapY,gapX2,gapY,itemSpacing+"px",gapColor);
|
|
630
|
+
}else{
|
|
631
|
+
// Vertical gap: horizontal marker between children
|
|
632
|
+
var gapY1=compY+c1.y+c1.h;
|
|
633
|
+
var gapY2=compY+c2.y;
|
|
634
|
+
var gapX=compX+cW+20;
|
|
635
|
+
drawDim(canvas,gapX,gapY1,gapX,gapY2,itemSpacing+"px",gapColor);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// ── Overall width/height dimension lines ──
|
|
641
|
+
// Width line below component
|
|
642
|
+
var dimY=compY+cH+50;
|
|
643
|
+
drawDim(canvas,compX,dimY,compX+cW,dimY,cW+"px",${C.textMuted});
|
|
644
|
+
// Height line left of component
|
|
645
|
+
var dimX=compX-40;
|
|
646
|
+
drawDim(canvas,dimX,compY,dimX,compY+cH,cH+"px",${C.textMuted});
|
|
647
|
+
|
|
648
|
+
// Resize canvas to fit all annotations
|
|
649
|
+
canvas.resize(Math.max(cW+AM*2+60,canvas.width),cH+AM*2+20);
|
|
650
|
+
})();
|
|
651
|
+
${spacerJS(16)}
|
|
652
|
+
`;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// ── Main script builder ─────────────────────────────────────────────────
|
|
656
|
+
|
|
657
|
+
export function buildSpecSheetScript(plan: SpecSheetPlan): string {
|
|
658
|
+
const sections = plan.sections;
|
|
659
|
+
const hasHeader = sections.includes("header");
|
|
660
|
+
const hasAnatomy = sections.includes("anatomy");
|
|
661
|
+
const hasProperties = sections.includes("properties");
|
|
662
|
+
const hasSpacing = sections.includes("spacing");
|
|
663
|
+
|
|
664
|
+
return `(async () => {
|
|
665
|
+
await figma.loadAllPagesAsync();
|
|
666
|
+
${FL}
|
|
667
|
+
|
|
668
|
+
// Resolve source node
|
|
669
|
+
var sourceNode = await figma.getNodeByIdAsync(${esc(plan.sourceNodeId)});
|
|
670
|
+
if (!sourceNode) throw new Error("Source node not found: ${plan.sourceNodeId}");
|
|
671
|
+
|
|
672
|
+
// Deep style extraction helper (used by Properties section)
|
|
673
|
+
${hasProperties ? EXTRACT_STYLE_FN : ""}
|
|
674
|
+
|
|
675
|
+
// ── Master frame ──
|
|
676
|
+
var m = figma.createFrame();
|
|
677
|
+
m.name = ${esc(plan.componentName + " — Spec Sheet")};
|
|
678
|
+
m.layoutMode = "VERTICAL";
|
|
679
|
+
m.primaryAxisSizingMode = "AUTO";
|
|
680
|
+
m.counterAxisSizingMode = "FIXED";
|
|
681
|
+
m.resize(${PAGE_W}, 100);
|
|
682
|
+
m.paddingTop = ${PAD};
|
|
683
|
+
m.paddingBottom = ${PAD};
|
|
684
|
+
m.paddingLeft = ${PAD};
|
|
685
|
+
m.paddingRight = ${PAD};
|
|
686
|
+
m.itemSpacing = 0;
|
|
687
|
+
m.fills = [{ type: "SOLID", color: ${C.white} }];
|
|
688
|
+
m.clipsContent = false;
|
|
689
|
+
m.x = ${plan.placement.x};
|
|
690
|
+
m.y = ${plan.placement.y};
|
|
691
|
+
figma.currentPage.appendChild(m);
|
|
692
|
+
|
|
693
|
+
${hasHeader ? buildHeaderJS(plan) : ""}
|
|
694
|
+
${hasAnatomy ? buildAnatomyJS(plan) : ""}
|
|
695
|
+
${hasProperties ? buildPropertiesJS(plan) : ""}
|
|
696
|
+
${hasSpacing ? buildSpacingJS(plan) : ""}
|
|
697
|
+
|
|
698
|
+
figma.viewport.scrollAndZoomIntoView([m]);
|
|
699
|
+
return { frameId: m.id };
|
|
700
|
+
})();`;
|
|
701
|
+
}
|