@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.
Files changed (286) hide show
  1. package/LICENSE +26 -0
  2. package/README.md +327 -0
  3. package/bin/cli.js +859 -0
  4. package/design-bridge/.env.example +5 -0
  5. package/design-bridge/bridge.js +196 -0
  6. package/design-bridge/lib/assets.js +367 -0
  7. package/design-bridge/lib/prompt.js +85 -0
  8. package/design-bridge/lib/server.js +66 -0
  9. package/design-bridge/lib/stitch.js +37 -0
  10. package/design-bridge/lib/tokens.js +82 -0
  11. package/design-bridge/package-lock.json +579 -0
  12. package/design-bridge/package.json +19 -0
  13. package/figma-bridge-plugin/README.md +97 -0
  14. package/figma-bridge-plugin/anthropic-chat-runner.js +192 -0
  15. package/figma-bridge-plugin/bridge-relay.js +2363 -0
  16. package/figma-bridge-plugin/chat-runner.js +459 -0
  17. package/figma-bridge-plugin/code.js +1528 -0
  18. package/figma-bridge-plugin/codex-runner.js +505 -0
  19. package/figma-bridge-plugin/component-schemas.js +110 -0
  20. package/figma-bridge-plugin/content-context.js +869 -0
  21. package/figma-bridge-plugin/create-button.js +216 -0
  22. package/figma-bridge-plugin/gemini-cli-runner.js +291 -0
  23. package/figma-bridge-plugin/gemini-runner.js +187 -0
  24. package/figma-bridge-plugin/html-to-figma.js +927 -0
  25. package/figma-bridge-plugin/knowledge-hub/.gitkeep +0 -0
  26. package/figma-bridge-plugin/knowledge-hub/uspec-references/anatomy-spec.md +159 -0
  27. package/figma-bridge-plugin/knowledge-hub/uspec-references/api-spec.md +162 -0
  28. package/figma-bridge-plugin/knowledge-hub/uspec-references/color-spec.md +148 -0
  29. package/figma-bridge-plugin/knowledge-hub/uspec-references/full-spec-template.md +314 -0
  30. package/figma-bridge-plugin/knowledge-hub/uspec-references/property-spec.md +175 -0
  31. package/figma-bridge-plugin/knowledge-hub/uspec-references/screen-reader-spec.md +180 -0
  32. package/figma-bridge-plugin/knowledge-hub/uspec-references/structure-spec.md +165 -0
  33. package/figma-bridge-plugin/manifest.json +21 -0
  34. package/figma-bridge-plugin/package-lock.json +1936 -0
  35. package/figma-bridge-plugin/package.json +20 -0
  36. package/figma-bridge-plugin/perplexity-runner.js +188 -0
  37. package/figma-bridge-plugin/references/SKILL.md +178 -0
  38. package/figma-bridge-plugin/references/anatomy-spec.md +159 -0
  39. package/figma-bridge-plugin/references/api-spec.md +162 -0
  40. package/figma-bridge-plugin/references/color-spec.md +148 -0
  41. package/figma-bridge-plugin/references/full-spec-template.md +314 -0
  42. package/figma-bridge-plugin/references/property-spec.md +175 -0
  43. package/figma-bridge-plugin/references/screen-reader-spec.md +180 -0
  44. package/figma-bridge-plugin/references/structure-spec.md +165 -0
  45. package/figma-bridge-plugin/shared-prompt-config.js +604 -0
  46. package/figma-bridge-plugin/spec-helpers/build-table.js +269 -0
  47. package/figma-bridge-plugin/spec-helpers/classify-elements.js +189 -0
  48. package/figma-bridge-plugin/spec-helpers/index.js +35 -0
  49. package/figma-bridge-plugin/spec-helpers/parse-figma-link.js +49 -0
  50. package/figma-bridge-plugin/spec-helpers/position-markers.js +158 -0
  51. package/figma-bridge-plugin/stitch-auth.js +322 -0
  52. package/figma-bridge-plugin/stitch-runner.js +1427 -0
  53. package/figma-bridge-plugin/token-resolver.js +107 -0
  54. package/figma-bridge-plugin/ui.html +4467 -0
  55. package/figma-intelligence-layer/.env.example +39 -0
  56. package/figma-intelligence-layer/docs/local-image-generation.md +60 -0
  57. package/figma-intelligence-layer/examples/comfyui-workflow-template.example.json +101 -0
  58. package/figma-intelligence-layer/jest.config.js +14 -0
  59. package/figma-intelligence-layer/mcp-config.json +19 -0
  60. package/figma-intelligence-layer/package-lock.json +5892 -0
  61. package/figma-intelligence-layer/package.json +48 -0
  62. package/figma-intelligence-layer/scripts/setup-comfyui-local.sh +67 -0
  63. package/figma-intelligence-layer/scripts/start-comfyui.sh +33 -0
  64. package/figma-intelligence-layer/src/index.ts +2233 -0
  65. package/figma-intelligence-layer/src/shared/auto-layout-validator.ts +404 -0
  66. package/figma-intelligence-layer/src/shared/cache.ts +187 -0
  67. package/figma-intelligence-layer/src/shared/color-operations.ts +533 -0
  68. package/figma-intelligence-layer/src/shared/color-utils.ts +138 -0
  69. package/figma-intelligence-layer/src/shared/component-script-builder.ts +413 -0
  70. package/figma-intelligence-layer/src/shared/component-templates.ts +2767 -0
  71. package/figma-intelligence-layer/src/shared/concept-taxonomy.ts +694 -0
  72. package/figma-intelligence-layer/src/shared/decision-log.ts +128 -0
  73. package/figma-intelligence-layer/src/shared/design-system-context.ts +568 -0
  74. package/figma-intelligence-layer/src/shared/design-system-intelligence.ts +131 -0
  75. package/figma-intelligence-layer/src/shared/design-system-matcher.ts +184 -0
  76. package/figma-intelligence-layer/src/shared/design-system-normalizers.ts +196 -0
  77. package/figma-intelligence-layer/src/shared/design-system-tokens.ts +295 -0
  78. package/figma-intelligence-layer/src/shared/dtcg-validator.ts +530 -0
  79. package/figma-intelligence-layer/src/shared/enrichment-pipeline.ts +671 -0
  80. package/figma-intelligence-layer/src/shared/figma-bridge.ts +1408 -0
  81. package/figma-intelligence-layer/src/shared/font-config.ts +126 -0
  82. package/figma-intelligence-layer/src/shared/icon-catalog.ts +360 -0
  83. package/figma-intelligence-layer/src/shared/icon-fetch.ts +80 -0
  84. package/figma-intelligence-layer/src/shared/prototype-script-builder.ts +162 -0
  85. package/figma-intelligence-layer/src/shared/response-compression.ts +440 -0
  86. package/figma-intelligence-layer/src/shared/semantic-token-catalog.ts +324 -0
  87. package/figma-intelligence-layer/src/shared/token-binder.ts +505 -0
  88. package/figma-intelligence-layer/src/shared/token-math.ts +427 -0
  89. package/figma-intelligence-layer/src/shared/token-naming.ts +468 -0
  90. package/figma-intelligence-layer/src/shared/token-utils.ts +420 -0
  91. package/figma-intelligence-layer/src/shared/types.ts +346 -0
  92. package/figma-intelligence-layer/src/shared/typography-presets.ts +94 -0
  93. package/figma-intelligence-layer/src/shared/unsplash.ts +165 -0
  94. package/figma-intelligence-layer/src/shared/vision-client.ts +607 -0
  95. package/figma-intelligence-layer/src/shared/vision-provider-anthropic.ts +334 -0
  96. package/figma-intelligence-layer/src/shared/vision-provider-openai.ts +446 -0
  97. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-handler.ts +782 -0
  98. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotate-renderer.ts +496 -0
  99. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/a11y-annotation-kit.ts +230 -0
  100. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/colorblind-sim.ts +66 -0
  101. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/index.ts +810 -0
  102. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-analyzer.ts +1191 -0
  103. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-figma-page.ts +1346 -0
  104. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/keyboard-sr-order-handler.ts +148 -0
  105. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-figma-page.ts +499 -0
  106. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/vpat-report.ts +910 -0
  107. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-checker.ts +989 -0
  108. package/figma-intelligence-layer/src/tools/phase1-vision/a11y-audit/wcag-criteria.ts +1160 -0
  109. package/figma-intelligence-layer/src/tools/phase1-vision/design-from-ref/index.ts +424 -0
  110. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/component-recognizer.ts +38 -0
  111. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/ds-matcher.ts +111 -0
  112. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/font-matcher.ts +114 -0
  113. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/icon-resolver.ts +103 -0
  114. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/index.ts +1060 -0
  115. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/layout-segmenter.ts +18 -0
  116. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/token-inferencer.ts +39 -0
  117. package/figma-intelligence-layer/src/tools/phase1-vision/screen-cloner/vision-pipeline.ts +58 -0
  118. package/figma-intelligence-layer/src/tools/phase1-vision/sketch-to-design/index.ts +298 -0
  119. package/figma-intelligence-layer/src/tools/phase1-vision/visual-audit/index.ts +197 -0
  120. package/figma-intelligence-layer/src/tools/phase2-accuracy/component-audit/index.ts +494 -0
  121. package/figma-intelligence-layer/src/tools/phase2-accuracy/intent-translator/index.ts +356 -0
  122. package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/container-patterns.ts +123 -0
  123. package/figma-intelligence-layer/src/tools/phase2-accuracy/layout-intelligence/index.ts +663 -0
  124. package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/built-in-rules.yaml +56 -0
  125. package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/index.ts +614 -0
  126. package/figma-intelligence-layer/src/tools/phase2-accuracy/lint-rules/rule-engine.ts +113 -0
  127. package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/color-theory.ts +178 -0
  128. package/figma-intelligence-layer/src/tools/phase2-accuracy/theme-generator/index.ts +470 -0
  129. package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/index.ts +429 -0
  130. package/figma-intelligence-layer/src/tools/phase2-accuracy/variant-expander/token-override-maps.ts +226 -0
  131. package/figma-intelligence-layer/src/tools/phase3-generation/ai-image-insert/index.ts +535 -0
  132. package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/index.ts +660 -0
  133. package/figma-intelligence-layer/src/tools/phase3-generation/component-archaeologist/pattern-fingerprints.ts +209 -0
  134. package/figma-intelligence-layer/src/tools/phase3-generation/composition-builder/index.ts +540 -0
  135. package/figma-intelligence-layer/src/tools/phase3-generation/figma-animated-build.ts +391 -0
  136. package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/index.ts +2019 -0
  137. package/figma-intelligence-layer/src/tools/phase3-generation/page-architect/screen-templates.ts +131 -0
  138. package/figma-intelligence-layer/src/tools/phase3-generation/prototype-map/index.ts +381 -0
  139. package/figma-intelligence-layer/src/tools/phase3-generation/prototype-wire/index.ts +565 -0
  140. package/figma-intelligence-layer/src/tools/phase3-generation/swarm-build/index.ts +764 -0
  141. package/figma-intelligence-layer/src/tools/phase3-generation/system-drift/index.ts +535 -0
  142. package/figma-intelligence-layer/src/tools/phase3-generation/unsplash-search/index.ts +84 -0
  143. package/figma-intelligence-layer/src/tools/phase3-generation/url-to-frame/index.ts +401 -0
  144. package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/css-animations.ts +68 -0
  145. package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/framer-motion.ts +78 -0
  146. package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/code-generators/swift-animations.ts +93 -0
  147. package/figma-intelligence-layer/src/tools/phase4-sync/animation-specifier/index.ts +596 -0
  148. package/figma-intelligence-layer/src/tools/phase4-sync/ci-check/index.ts +462 -0
  149. package/figma-intelligence-layer/src/tools/phase4-sync/export-tokens/index.ts +1470 -0
  150. package/figma-intelligence-layer/src/tools/phase4-sync/generate-component-code/index.ts +829 -0
  151. package/figma-intelligence-layer/src/tools/phase4-sync/handoff-spec/index.ts +702 -0
  152. package/figma-intelligence-layer/src/tools/phase4-sync/icon-library-sync/index.ts +483 -0
  153. package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/index.ts +501 -0
  154. package/figma-intelligence-layer/src/tools/phase4-sync/sync-from-code/storybook-parser.ts +106 -0
  155. package/figma-intelligence-layer/src/tools/phase4-sync/watch-docs/index.ts +676 -0
  156. package/figma-intelligence-layer/src/tools/phase4-sync/webhook-listener/index.ts +560 -0
  157. package/figma-intelligence-layer/src/tools/phase5-governance/apg-doc/index.ts +1043 -0
  158. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/component-detection.ts +620 -0
  159. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/anatomy.ts +331 -0
  160. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/color-tokens.ts +77 -0
  161. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/properties.ts +54 -0
  162. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/snapshot.ts +287 -0
  163. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/spacing.ts +71 -0
  164. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/states.ts +43 -0
  165. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/extractors/typography.ts +71 -0
  166. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/index.ts +221 -0
  167. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/_default.ts +166 -0
  168. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/accordion.ts +232 -0
  169. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/alert.ts +234 -0
  170. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar-group.ts +270 -0
  171. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/avatar.ts +249 -0
  172. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/badge.ts +231 -0
  173. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/banner.ts +293 -0
  174. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/breadcrumb.ts +240 -0
  175. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/button.ts +243 -0
  176. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/calendar.ts +307 -0
  177. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/card.ts +143 -0
  178. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/checkbox.ts +227 -0
  179. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/chip.ts +233 -0
  180. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/combobox.ts +282 -0
  181. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/datepicker.ts +276 -0
  182. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/divider.ts +223 -0
  183. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/drawer.ts +255 -0
  184. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/dropdown-menu.ts +289 -0
  185. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/empty-state.ts +261 -0
  186. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/file-uploader.ts +290 -0
  187. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/form.ts +265 -0
  188. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/grid.ts +238 -0
  189. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/icon.ts +255 -0
  190. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/index.ts +128 -0
  191. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-edit.ts +286 -0
  192. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/inline-message.ts +255 -0
  193. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/input.ts +330 -0
  194. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/link.ts +247 -0
  195. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/list.ts +250 -0
  196. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/menu.ts +247 -0
  197. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/modal.ts +144 -0
  198. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navbar.ts +264 -0
  199. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/navigation.ts +251 -0
  200. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/number-input.ts +261 -0
  201. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/pagination.ts +248 -0
  202. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/popover.ts +270 -0
  203. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/progress.ts +251 -0
  204. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/radio.ts +142 -0
  205. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/range-slider.ts +282 -0
  206. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/rating.ts +250 -0
  207. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/search.ts +258 -0
  208. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/segmented-control.ts +265 -0
  209. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/select.ts +319 -0
  210. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/skeleton.ts +256 -0
  211. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/slider.ts +232 -0
  212. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/spinner.ts +239 -0
  213. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/status-dot.ts +252 -0
  214. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/stepper.ts +270 -0
  215. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/table.ts +244 -0
  216. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tabs.ts +143 -0
  217. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tag.ts +243 -0
  218. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/textarea.ts +259 -0
  219. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/time-picker.ts +293 -0
  220. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toast.ts +144 -0
  221. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toggle.ts +289 -0
  222. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/toolbar.ts +267 -0
  223. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/tooltip.ts +232 -0
  224. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/treeview.ts +257 -0
  225. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/knowledge/typography.ts +319 -0
  226. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/legacy-compat.ts +121 -0
  227. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/anatomy-diagram.ts +430 -0
  228. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/figma-page.ts +312 -0
  229. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/json.ts +129 -0
  230. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/markdown.ts +78 -0
  231. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/renderers/visual-doc.ts +2333 -0
  232. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/accessibility.ts +100 -0
  233. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/anatomy.ts +32 -0
  234. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/color-tokens.ts +59 -0
  235. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/content-guidance.ts +18 -0
  236. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/design-tokens.ts +53 -0
  237. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/interaction-rules.ts +19 -0
  238. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/overview.ts +91 -0
  239. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/properties-api.ts +71 -0
  240. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/qa-criteria.ts +19 -0
  241. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/related-components.ts +110 -0
  242. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/responsive.ts +19 -0
  243. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/size-specs.ts +67 -0
  244. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/spacing-structure.ts +58 -0
  245. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/state-specs.ts +79 -0
  246. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/states.ts +50 -0
  247. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/type-hierarchy.ts +33 -0
  248. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/typography.ts +55 -0
  249. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/usage-guidelines.ts +73 -0
  250. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/sections/variants.ts +81 -0
  251. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec/types.ts +409 -0
  252. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/index.ts +198 -0
  253. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/renderer.ts +701 -0
  254. package/figma-intelligence-layer/src/tools/phase5-governance/component-spec-sheet/types.ts +88 -0
  255. package/figma-intelligence-layer/src/tools/phase5-governance/decision-log/index.ts +135 -0
  256. package/figma-intelligence-layer/src/tools/phase5-governance/design-decision-log/index.ts +491 -0
  257. package/figma-intelligence-layer/src/tools/phase5-governance/ds-primitives/index.ts +416 -0
  258. package/figma-intelligence-layer/src/tools/phase5-governance/ds-scaffolder/index.ts +722 -0
  259. package/figma-intelligence-layer/src/tools/phase5-governance/ds-variables/index.ts +449 -0
  260. package/figma-intelligence-layer/src/tools/phase5-governance/health-report/index.ts +393 -0
  261. package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/index.ts +406 -0
  262. package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/figma-page.ts +292 -0
  263. package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/json.ts +24 -0
  264. package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/markdown.ts +172 -0
  265. package/figma-intelligence-layer/src/tools/phase5-governance/taxonomy-docs/renderers/naming-guide.ts +409 -0
  266. package/figma-intelligence-layer/src/tools/phase5-governance/token-analytics/index.ts +594 -0
  267. package/figma-intelligence-layer/src/tools/phase5-governance/token-docs/index.ts +710 -0
  268. package/figma-intelligence-layer/src/tools/phase5-governance/token-migrate/index.ts +458 -0
  269. package/figma-intelligence-layer/src/tools/phase5-governance/token-naming/index.ts +134 -0
  270. package/figma-intelligence-layer/tests/apg-doc.test.ts +101 -0
  271. package/figma-intelligence-layer/tests/design-system-context.test.ts +152 -0
  272. package/figma-intelligence-layer/tests/design-system-matcher.test.ts +144 -0
  273. package/figma-intelligence-layer/tests/figma-bridge.test.ts +83 -0
  274. package/figma-intelligence-layer/tests/generate-image-and-insert.test.ts +56 -0
  275. package/figma-intelligence-layer/tests/screen-cloner-regression.test.ts +69 -0
  276. package/figma-intelligence-layer/tests/smoke.test.ts +174 -0
  277. package/figma-intelligence-layer/tests/spec-generator.test.ts +127 -0
  278. package/figma-intelligence-layer/tests/token-migrate.test.ts +21 -0
  279. package/figma-intelligence-layer/tests/token-naming.test.ts +30 -0
  280. package/figma-intelligence-layer/tsconfig.json +19 -0
  281. package/package.json +35 -0
  282. package/scripts/clean-existing-chunks.js +179 -0
  283. package/scripts/connect-ai-tool.js +490 -0
  284. package/scripts/convert-hub-pdfs.js +425 -0
  285. package/scripts/figma-mcp-status.js +349 -0
  286. package/scripts/register-codex-mcp.js +96 -0
@@ -0,0 +1,1346 @@
1
+ /**
2
+ * Keyboard & Screen Reader Order — Figma Page Renderer
3
+ * Renders the full accessibility annotation as an enterprise-quality Figma page
4
+ * with auto-layout tables, callout boxes, and structured sections.
5
+ *
6
+ * IMPORTANT Figma Plugin API pattern:
7
+ * layoutSizingHorizontal = "FILL" only works AFTER the node is appended
8
+ * to an auto-layout parent. Always: appendChild() first, then set sizing.
9
+ */
10
+
11
+ import type {
12
+ A11yOrderAnalysis,
13
+ TabOrderEntry,
14
+ ReadingOrderNode,
15
+ FocusAnnouncement,
16
+ StateChangeRule,
17
+ FocusRule,
18
+ AriaReq,
19
+ KBRule,
20
+ Warning,
21
+ AuditSummaryRow,
22
+ } from "./keyboard-sr-order-analyzer.js";
23
+
24
+ // ── Design Tokens ────────────────────────────────────────────────────────────
25
+
26
+ const PAGE_W = 1200;
27
+ const PAD = 50;
28
+ const CONTENT_W = PAGE_W - PAD * 2;
29
+
30
+ const C = {
31
+ textMain: "{r:0.067,g:0.094,b:0.153}",
32
+ textMuted: "{r:0.294,g:0.333,b:0.388}",
33
+ textWhite: "{r:1,g:1,b:1}",
34
+ bgPage: "{r:1,g:1,b:1}",
35
+ bgHeader: "{r:0.067,g:0.094,b:0.153}",
36
+ bgTableHeader: "{r:0.953,g:0.957,b:0.965}",
37
+ border: "{r:0.898,g:0.906,b:0.922}",
38
+ accent: "{r:0.2,g:0.45,b:0.9}",
39
+ warnBg: "{r:1,g:0.95,b:0.95}",
40
+ warnBorder: "{r:0.863,g:0.149,b:0.149}",
41
+ warnAmberBg: "{r:1,g:0.98,b:0.93}",
42
+ warnAmberBdr: "{r:0.918,g:0.576,b:0.051}",
43
+ infoBg: "{r:0.94,g:0.96,b:1}",
44
+ infoBorder: "{r:0.2,g:0.45,b:0.9}",
45
+ green: "{r:0.086,g:0.639,b:0.290}",
46
+ greenBg: "{r:0.863,g:0.965,b:0.898}",
47
+ };
48
+
49
+ type Bridge = {
50
+ execute(code: string): Promise<{ success: boolean; result?: unknown; error?: string }>;
51
+ };
52
+
53
+ function esc(s: string): string { return JSON.stringify(s); }
54
+
55
+ // ── Font Loader ──────────────────────────────────────────────────────────────
56
+
57
+ const FL = `
58
+ var F={};
59
+ 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){}}
60
+ await lf("b",[{family:"Inter",style:"Bold"},{family:"Roboto",style:"Bold"}]);
61
+ await lf("sb",[{family:"Inter",style:"SemiBold"},{family:"Inter",style:"Medium"},{family:"Roboto",style:"Medium"}]);
62
+ await lf("r",[{family:"Inter",style:"Regular"},{family:"Roboto",style:"Regular"}]);
63
+ await lf("mono",[{family:"Roboto Mono",style:"Regular"},{family:"Courier New",style:"Regular"}]);
64
+ `;
65
+
66
+ // ── Layout Helpers ───────────────────────────────────────────────────────────
67
+
68
+ function spacerJS(h: number, parent: string = "m"): string {
69
+ return `(function(){var sp=figma.createFrame();sp.resize(4,${h});sp.fills=[];${parent}.appendChild(sp);sp.layoutSizingHorizontal="FILL";})();`;
70
+ }
71
+
72
+ function dividerJS(parent: string = "m"): string {
73
+ return `(function(){var dv=figma.createRectangle();dv.resize(4,2);dv.fills=[{type:"SOLID",color:${C.border}}];${parent}.appendChild(dv);dv.layoutSizingHorizontal="FILL";})();`;
74
+ }
75
+
76
+ function sectionHeadingJS(title: string, parent: string = "m"): string {
77
+ return `(function(){
78
+ var t=figma.createText();t.fontName=F.b;t.fontSize=22;
79
+ t.lineHeight={unit:"PIXELS",value:30};
80
+ t.characters=${esc(title)};
81
+ t.fills=[{type:"SOLID",color:${C.textMain}}];
82
+ t.textAutoResize="HEIGHT";
83
+ ${parent}.appendChild(t);t.layoutSizingHorizontal="FILL";
84
+ })();`;
85
+ }
86
+
87
+ function truncate(text: string, maxLen: number): string {
88
+ if (text.length <= maxLen) return text;
89
+ return text.slice(0, maxLen - 3) + "...";
90
+ }
91
+
92
+ // ── Main Renderer ────────────────────────────────────────────────────────────
93
+
94
+ export async function renderKeyboardSrOrderPage(
95
+ bridge: Bridge,
96
+ analysis: A11yOrderAnalysis,
97
+ customPageName?: string,
98
+ ): Promise<{ pageId: string }> {
99
+ const pageName =
100
+ customPageName ||
101
+ `A11y \u2014 Keyboard & SR Order \u2014 ${analysis.header.frameName} \u2014 ${analysis.header.date}`;
102
+
103
+ // Step 1: Create page + master frame
104
+ const initResult = await bridge.execute(`
105
+ (async () => {
106
+ await figma.loadAllPagesAsync();
107
+ var nm=${esc(pageName)};
108
+ var mm=figma.root.children.filter(function(p){return p.name===nm;});
109
+ var pg;
110
+ if(mm.length>0){pg=mm[0];for(var d=1;d<mm.length;d++)mm[d].remove();}
111
+ else{pg=figma.createPage();}
112
+ pg.name=nm;
113
+ await figma.setCurrentPageAsync(pg);
114
+ var ch=pg.children.slice();
115
+ for(var i=0;i<ch.length;i++)ch[i].remove();
116
+
117
+ var m=figma.createFrame();
118
+ m.name="Keyboard & SR Order Annotation";
119
+ m.layoutMode="VERTICAL";
120
+ m.primaryAxisSizingMode="AUTO";
121
+ m.counterAxisSizingMode="FIXED";
122
+ m.resize(${PAGE_W},100);
123
+ m.paddingTop=${PAD};m.paddingBottom=${PAD};
124
+ m.paddingLeft=${PAD};m.paddingRight=${PAD};
125
+ m.itemSpacing=0;
126
+ m.fills=[{type:"SOLID",color:${C.bgPage}}];
127
+ m.clipsContent=false;
128
+ pg.appendChild(m);
129
+ return {pageId:pg.id,mId:m.id};
130
+ })();
131
+ `);
132
+ if (!initResult.success) throw new Error(`KSR init: ${initResult.error}`);
133
+ const { pageId, mId } = initResult.result as { pageId: string; mId: string };
134
+
135
+ // Step 2: Render header
136
+ await renderHeader(bridge, mId, analysis);
137
+
138
+ // Step 3: Scope & Assumptions
139
+ await renderScopeAndAssumptions(bridge, mId, analysis);
140
+
141
+ // Step 4: Keyboard Tab Order table
142
+ await renderTabOrderTable(bridge, mId, analysis.keyboardTabOrder);
143
+
144
+ // Step 5: Screen Reader Reading Order
145
+ await renderReadingOrder(bridge, mId, analysis.screenReaderReadingOrder);
146
+
147
+ // Step 6: Interaction Announcements
148
+ await renderInteractionAnnouncements(bridge, mId, analysis);
149
+
150
+ // Step 7: Focus Management
151
+ await renderFocusManagement(bridge, mId, analysis.focusManagement);
152
+
153
+ // Step 8: Implementation Notes
154
+ await renderImplementationNotes(bridge, mId, analysis);
155
+
156
+ // Step 9: Warnings
157
+ await renderWarnings(bridge, mId, analysis.warnings);
158
+
159
+ // Step 10: Audit Summary
160
+ await renderAuditSummary(bridge, mId, analysis.auditSummary);
161
+
162
+ // Final: Zoom to fit
163
+ await bridge.execute(`
164
+ (async () => {
165
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
166
+ if(m)figma.viewport.scrollAndZoomIntoView([m]);
167
+ return{ok:true};
168
+ })();
169
+ `);
170
+
171
+ return { pageId };
172
+ }
173
+
174
+ // ── Section Renderers ───────────────────────────────────────────────────────
175
+
176
+ async function renderHeader(
177
+ bridge: Bridge,
178
+ mId: string,
179
+ analysis: A11yOrderAnalysis
180
+ ): Promise<void> {
181
+ const h = analysis.header;
182
+ await bridge.execute(`
183
+ (async () => {
184
+ ${FL}
185
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
186
+ if(!m)return{error:"no master"};
187
+
188
+ var hdr=figma.createFrame();
189
+ hdr.name="Header";
190
+ hdr.layoutMode="VERTICAL";
191
+ hdr.primaryAxisSizingMode="AUTO";
192
+ hdr.counterAxisSizingMode="AUTO";
193
+ hdr.paddingTop=40;hdr.paddingBottom=40;
194
+ hdr.paddingLeft=40;hdr.paddingRight=40;
195
+ hdr.itemSpacing=12;
196
+ hdr.cornerRadius=12;
197
+ hdr.fills=[{type:"SOLID",color:${C.bgHeader}}];
198
+ m.appendChild(hdr);
199
+ hdr.layoutSizingHorizontal="FILL";
200
+
201
+ // Badge
202
+ var badge=figma.createFrame();
203
+ badge.name="Standard Badge";
204
+ badge.layoutMode="HORIZONTAL";
205
+ badge.primaryAxisSizingMode="AUTO";
206
+ badge.counterAxisSizingMode="AUTO";
207
+ badge.paddingTop=6;badge.paddingBottom=6;
208
+ badge.paddingLeft=14;badge.paddingRight=14;
209
+ badge.cornerRadius=6;
210
+ badge.fills=[{type:"SOLID",color:${C.accent}}];
211
+ hdr.appendChild(badge);
212
+ var bt=figma.createText();bt.fontName=F.sb;bt.fontSize=13;
213
+ bt.characters=${esc(h.standard)};
214
+ bt.fills=[{type:"SOLID",color:${C.textWhite}}];
215
+ badge.appendChild(bt);
216
+
217
+ // Title
218
+ var t1=figma.createText();t1.fontName=F.b;t1.fontSize=32;
219
+ t1.lineHeight={unit:"PIXELS",value:40};
220
+ t1.characters="Keyboard & Screen Reader Order";
221
+ t1.fills=[{type:"SOLID",color:${C.textWhite}}];
222
+ t1.textAutoResize="HEIGHT";
223
+ hdr.appendChild(t1);t1.layoutSizingHorizontal="FILL";
224
+
225
+ // Subtitle
226
+ var sub=figma.createText();sub.fontName=F.r;sub.fontSize=15;
227
+ sub.lineHeight={unit:"PIXELS",value:22};
228
+ sub.characters=${esc(`${h.frameName} \u00b7 ${h.date} \u00b7 Node ${h.nodeId}`)};
229
+ sub.fills=[{type:"SOLID",color:{r:0.7,g:0.75,b:0.82}}];
230
+ sub.textAutoResize="HEIGHT";
231
+ hdr.appendChild(sub);sub.layoutSizingHorizontal="FILL";
232
+
233
+ // Subtitle line 2
234
+ var sub2=figma.createText();sub2.fontName=F.r;sub2.fontSize=13;
235
+ sub2.lineHeight={unit:"PIXELS",value:20};
236
+ sub2.characters="Accessibility Annotation (Developer Handoff)";
237
+ sub2.fills=[{type:"SOLID",color:{r:0.6,g:0.65,b:0.72}}];
238
+ sub2.textAutoResize="HEIGHT";
239
+ hdr.appendChild(sub2);sub2.layoutSizingHorizontal="FILL";
240
+
241
+ return{ok:true};
242
+ })();
243
+ `);
244
+ }
245
+
246
+ async function renderScopeAndAssumptions(
247
+ bridge: Bridge,
248
+ mId: string,
249
+ analysis: A11yOrderAnalysis
250
+ ): Promise<void> {
251
+ const assumptionsText = analysis.assumptions
252
+ .map((a, i) => `\u2022 ${a}`)
253
+ .join("\\n");
254
+
255
+ await bridge.execute(`
256
+ (async () => {
257
+ ${FL}
258
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
259
+ if(!m)return{error:"no master"};
260
+
261
+ ${spacerJS(32)}
262
+ ${sectionHeadingJS("Scope")}
263
+ ${spacerJS(8)}
264
+
265
+ var scope=figma.createText();scope.fontName=F.r;scope.fontSize=14;
266
+ scope.lineHeight={unit:"PIXELS",value:22};
267
+ scope.characters=${esc(analysis.scope)};
268
+ scope.fills=[{type:"SOLID",color:${C.textMain}}];
269
+ scope.textAutoResize="HEIGHT";
270
+ m.appendChild(scope);scope.layoutSizingHorizontal="FILL";
271
+
272
+ ${spacerJS(24)}
273
+ ${sectionHeadingJS("Assumptions")}
274
+ ${spacerJS(8)}
275
+
276
+ var assumptions=figma.createText();assumptions.fontName=F.r;assumptions.fontSize=14;
277
+ assumptions.lineHeight={unit:"PIXELS",value:22};
278
+ assumptions.characters=${esc(analysis.assumptions.join("\n"))};
279
+ assumptions.fills=[{type:"SOLID",color:${C.textMuted}}];
280
+ assumptions.textAutoResize="HEIGHT";
281
+ m.appendChild(assumptions);assumptions.layoutSizingHorizontal="FILL";
282
+
283
+ ${spacerJS(16)}
284
+ ${dividerJS()}
285
+
286
+ return{ok:true};
287
+ })();
288
+ `);
289
+ }
290
+
291
+ async function renderTabOrderTable(
292
+ bridge: Bridge,
293
+ mId: string,
294
+ tabOrder: TabOrderEntry[]
295
+ ): Promise<void> {
296
+ const BATCH_SIZE = 15;
297
+ const COL = { num: 40, element: 220, role: 100, label: 300, notes: CONTENT_W - 40 - 220 - 100 - 300 - 32 };
298
+
299
+ // Section heading + table frame + header row
300
+ await bridge.execute(`
301
+ (async () => {
302
+ ${FL}
303
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
304
+ if(!m)return{error:"no master"};
305
+
306
+ ${spacerJS(32)}
307
+ ${sectionHeadingJS("Keyboard Tab Order")}
308
+ ${spacerJS(8)}
309
+
310
+ var desc=figma.createText();desc.fontName=F.r;desc.fontSize=13;
311
+ desc.lineHeight={unit:"PIXELS",value:20};
312
+ desc.characters="Complete linear tab sequence for all focusable elements. Static text (prices, labels, headings) is excluded.";
313
+ desc.fills=[{type:"SOLID",color:${C.textMuted}}];
314
+ desc.textAutoResize="HEIGHT";
315
+ m.appendChild(desc);desc.layoutSizingHorizontal="FILL";
316
+
317
+ ${spacerJS(12)}
318
+
319
+ var tbl=figma.createFrame();
320
+ tbl.name="Tab Order Table";
321
+ tbl.layoutMode="VERTICAL";
322
+ tbl.primaryAxisSizingMode="AUTO";
323
+ tbl.counterAxisSizingMode="AUTO";
324
+ tbl.itemSpacing=0;
325
+ tbl.fills=[{type:"SOLID",color:${C.bgPage}}];
326
+ tbl.cornerRadius=8;
327
+ tbl.strokes=[{type:"SOLID",color:${C.border}}];
328
+ tbl.strokeWeight=1;tbl.strokeAlign="INSIDE";
329
+ tbl.clipsContent=true;
330
+ m.appendChild(tbl);
331
+ tbl.layoutSizingHorizontal="FILL";
332
+
333
+ // Header row
334
+ var hdr=figma.createFrame();
335
+ hdr.name="Header";
336
+ hdr.layoutMode="HORIZONTAL";
337
+ hdr.primaryAxisSizingMode="AUTO";
338
+ hdr.counterAxisSizingMode="AUTO";
339
+ hdr.itemSpacing=0;
340
+ hdr.paddingTop=12;hdr.paddingBottom=12;
341
+ hdr.paddingLeft=16;hdr.paddingRight=16;
342
+ hdr.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
343
+ hdr.counterAxisAlignItems="MIN";
344
+ hdr.strokes=[{type:"SOLID",color:${C.border}}];
345
+ hdr.strokeWeight=1;
346
+ hdr.strokeTopWeight=0;hdr.strokeRightWeight=0;
347
+ hdr.strokeBottomWeight=1;hdr.strokeLeftWeight=0;
348
+ hdr.strokeAlign="INSIDE";
349
+ tbl.appendChild(hdr);
350
+ hdr.layoutSizingHorizontal="FILL";
351
+
352
+ var hLabels=["#","Element","Role","Label","Notes"];
353
+ var hWidths=[${COL.num},${COL.element},${COL.role},${COL.label},${COL.notes}];
354
+ for(var c=0;c<hLabels.length;c++){
355
+ var ht=figma.createText();ht.fontName=F.sb;ht.fontSize=12;
356
+ ht.lineHeight={unit:"PIXELS",value:18};
357
+ ht.characters=hLabels[c];
358
+ ht.fills=[{type:"SOLID",color:${C.textMain}}];
359
+ ht.textAutoResize="HEIGHT";
360
+ ht.resize(hWidths[c],18);
361
+ hdr.appendChild(ht);ht.layoutSizingHorizontal="FIXED";
362
+ }
363
+
364
+ return{tblId:tbl.id};
365
+ })();
366
+ `);
367
+
368
+ // Render data rows in batches
369
+ for (let i = 0; i < tabOrder.length; i += BATCH_SIZE) {
370
+ const batch = tabOrder.slice(i, i + BATCH_SIZE);
371
+ const rows = batch.map((r) => ({
372
+ num: String(r.order),
373
+ element: truncate(r.elementDescription, 50),
374
+ role: r.role,
375
+ label: truncate(r.label, 60),
376
+ notes: truncate(r.notes, 80),
377
+ }));
378
+
379
+ await bridge.execute(`
380
+ (async () => {
381
+ ${FL}
382
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
383
+ if(!m)return{error:"no master"};
384
+ // Find the table frame
385
+ var tbl=null;
386
+ for(var i=0;i<m.children.length;i++){
387
+ if(m.children[i].name==="Tab Order Table"){tbl=m.children[i];break;}
388
+ }
389
+ if(!tbl)return{error:"no table"};
390
+
391
+ var rows=${JSON.stringify(rows)};
392
+ var widths=[${COL.num},${COL.element},${COL.role},${COL.label},${COL.notes}];
393
+ var keys=["num","element","role","label","notes"];
394
+
395
+ for(var ri=0;ri<rows.length;ri++){
396
+ var d=rows[ri];
397
+ var row=figma.createFrame();
398
+ row.name="Row "+(${i}+ri+1);
399
+ row.layoutMode="HORIZONTAL";
400
+ row.primaryAxisSizingMode="AUTO";
401
+ row.counterAxisSizingMode="AUTO";
402
+ row.itemSpacing=0;
403
+ row.paddingTop=10;row.paddingBottom=10;
404
+ row.paddingLeft=16;row.paddingRight=16;
405
+ row.fills=[];
406
+ row.counterAxisAlignItems="MIN";
407
+ row.strokes=[{type:"SOLID",color:${C.border}}];
408
+ row.strokeWeight=1;
409
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
410
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
411
+ row.strokeAlign="INSIDE";
412
+ tbl.appendChild(row);
413
+ row.layoutSizingHorizontal="FILL";
414
+
415
+ for(var c=0;c<keys.length;c++){
416
+ var ct=figma.createText();
417
+ ct.fontName=c===0?F.sb:(c===2?F.mono:F.r);
418
+ ct.fontSize=12;
419
+ ct.lineHeight={unit:"PIXELS",value:18};
420
+ ct.characters=d[keys[c]]||"\\u2014";
421
+ ct.fills=[{type:"SOLID",color:c===2?${C.accent}:${C.textMain}}];
422
+ ct.textAutoResize="HEIGHT";
423
+ ct.resize(widths[c],18);
424
+ row.appendChild(ct);ct.layoutSizingHorizontal="FIXED";
425
+ }
426
+ }
427
+
428
+ return{ok:true};
429
+ })();
430
+ `);
431
+ }
432
+ }
433
+
434
+ async function renderReadingOrder(
435
+ bridge: Bridge,
436
+ mId: string,
437
+ readingOrder: ReadingOrderNode[]
438
+ ): Promise<void> {
439
+ // Flatten reading order into numbered lines with indentation
440
+ const lines: { text: string; indent: number }[] = [];
441
+ let counter = 1;
442
+
443
+ function flattenNodes(nodes: ReadingOrderNode[], depth: number): void {
444
+ for (const node of nodes) {
445
+ if (node.landmarkRole) {
446
+ lines.push({
447
+ text: `${counter++}. ${node.landmarkLabel || node.landmarkRole} region`,
448
+ indent: depth,
449
+ });
450
+ if (node.children) flattenNodes(node.children, depth + 1);
451
+ } else if (node.children && node.children.length > 0) {
452
+ lines.push({
453
+ text: `${counter++}. ${node.content}`,
454
+ indent: depth,
455
+ });
456
+ flattenNodes(node.children, depth + 1);
457
+ } else {
458
+ const roleTag = node.role ? ` (${node.role})` : "";
459
+ lines.push({
460
+ text: `${counter++}. ${node.content}${roleTag}`,
461
+ indent: depth,
462
+ });
463
+ }
464
+ }
465
+ }
466
+
467
+ flattenNodes(readingOrder, 0);
468
+
469
+ // Limit to keep script manageable
470
+ const displayLines = lines.slice(0, 60);
471
+
472
+ await bridge.execute(`
473
+ (async () => {
474
+ ${FL}
475
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
476
+ if(!m)return{error:"no master"};
477
+
478
+ ${spacerJS(32)}
479
+ ${sectionHeadingJS("Screen Reader Reading Order")}
480
+ ${spacerJS(8)}
481
+
482
+ var desc=figma.createText();desc.fontName=F.r;desc.fontSize=13;
483
+ desc.lineHeight={unit:"PIXELS",value:20};
484
+ desc.characters="Virtual cursor (Browse mode) reading order, reflecting DOM order inferred from auto-layout hierarchy:";
485
+ desc.fills=[{type:"SOLID",color:${C.textMuted}}];
486
+ desc.textAutoResize="HEIGHT";
487
+ m.appendChild(desc);desc.layoutSizingHorizontal="FILL";
488
+
489
+ ${spacerJS(12)}
490
+
491
+ var list=figma.createFrame();
492
+ list.name="Reading Order List";
493
+ list.layoutMode="VERTICAL";
494
+ list.primaryAxisSizingMode="AUTO";
495
+ list.counterAxisSizingMode="AUTO";
496
+ list.itemSpacing=4;
497
+ list.paddingTop=16;list.paddingBottom=16;
498
+ list.paddingLeft=20;list.paddingRight=20;
499
+ list.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
500
+ list.cornerRadius=8;
501
+ m.appendChild(list);
502
+ list.layoutSizingHorizontal="FILL";
503
+
504
+ var lines=${JSON.stringify(displayLines)};
505
+ for(var i=0;i<lines.length;i++){
506
+ var ln=lines[i];
507
+ var row=figma.createFrame();
508
+ row.name="Line "+(i+1);
509
+ row.layoutMode="HORIZONTAL";
510
+ row.primaryAxisSizingMode="AUTO";
511
+ row.counterAxisSizingMode="AUTO";
512
+ row.paddingLeft=ln.indent*24;
513
+ row.fills=[];
514
+ row.itemSpacing=0;
515
+ list.appendChild(row);
516
+ row.layoutSizingHorizontal="FILL";
517
+
518
+ var txt=figma.createText();
519
+ txt.fontName=ln.indent===0?F.sb:F.r;
520
+ txt.fontSize=ln.indent===0?14:13;
521
+ txt.lineHeight={unit:"PIXELS",value:ln.indent===0?22:20};
522
+ txt.characters=ln.text;
523
+ txt.fills=[{type:"SOLID",color:ln.indent===0?${C.textMain}:${C.textMuted}}];
524
+ txt.textAutoResize="HEIGHT";
525
+ row.appendChild(txt);txt.layoutSizingHorizontal="FILL";
526
+ }
527
+
528
+ ${spacerJS(16)}
529
+ ${dividerJS()}
530
+
531
+ return{ok:true};
532
+ })();
533
+ `);
534
+ }
535
+
536
+ async function renderInteractionAnnouncements(
537
+ bridge: Bridge,
538
+ mId: string,
539
+ analysis: A11yOrderAnalysis
540
+ ): Promise<void> {
541
+ const focusRows = analysis.interactionAnnouncements.onFocus.map((f) => ({
542
+ element: truncate(f.element, 50),
543
+ announcement: truncate(f.announcement, 80),
544
+ }));
545
+ const stateRows = analysis.interactionAnnouncements.stateChanges.map(
546
+ (s) => ({
547
+ trigger: truncate(s.trigger, 50),
548
+ behavior: truncate(s.behavior, 100),
549
+ })
550
+ );
551
+
552
+ // Limit focus rows for rendering
553
+ const displayFocusRows = focusRows.slice(0, 25);
554
+
555
+ const COL_FOCUS = { element: 320, announcement: CONTENT_W - 320 - 32 };
556
+ const COL_STATE = { trigger: 320, behavior: CONTENT_W - 320 - 32 };
557
+
558
+ await bridge.execute(`
559
+ (async () => {
560
+ ${FL}
561
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
562
+ if(!m)return{error:"no master"};
563
+
564
+ ${spacerJS(32)}
565
+ ${sectionHeadingJS("Screen Reader Interaction Announcements")}
566
+ ${spacerJS(16)}
567
+
568
+ // Sub-heading: On Focus
569
+ var sh1=figma.createText();sh1.fontName=F.sb;sh1.fontSize=16;
570
+ sh1.lineHeight={unit:"PIXELS",value:24};
571
+ sh1.characters="On Focus";
572
+ sh1.fills=[{type:"SOLID",color:${C.textMain}}];
573
+ sh1.textAutoResize="HEIGHT";
574
+ m.appendChild(sh1);sh1.layoutSizingHorizontal="FILL";
575
+
576
+ ${spacerJS(8)}
577
+
578
+ // Focus announcements table
579
+ var tbl1=figma.createFrame();
580
+ tbl1.name="Focus Announcements";
581
+ tbl1.layoutMode="VERTICAL";
582
+ tbl1.primaryAxisSizingMode="AUTO";
583
+ tbl1.counterAxisSizingMode="AUTO";
584
+ tbl1.itemSpacing=0;
585
+ tbl1.fills=[{type:"SOLID",color:${C.bgPage}}];
586
+ tbl1.cornerRadius=8;
587
+ tbl1.strokes=[{type:"SOLID",color:${C.border}}];
588
+ tbl1.strokeWeight=1;tbl1.strokeAlign="INSIDE";
589
+ tbl1.clipsContent=true;
590
+ m.appendChild(tbl1);
591
+ tbl1.layoutSizingHorizontal="FILL";
592
+
593
+ // Header
594
+ var hdr1=figma.createFrame();
595
+ hdr1.name="Header";
596
+ hdr1.layoutMode="HORIZONTAL";
597
+ hdr1.primaryAxisSizingMode="AUTO";
598
+ hdr1.counterAxisSizingMode="AUTO";
599
+ hdr1.itemSpacing=0;
600
+ hdr1.paddingTop=12;hdr1.paddingBottom=12;
601
+ hdr1.paddingLeft=16;hdr1.paddingRight=16;
602
+ hdr1.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
603
+ hdr1.counterAxisAlignItems="MIN";
604
+ hdr1.strokes=[{type:"SOLID",color:${C.border}}];
605
+ hdr1.strokeWeight=1;
606
+ hdr1.strokeTopWeight=0;hdr1.strokeRightWeight=0;
607
+ hdr1.strokeBottomWeight=1;hdr1.strokeLeftWeight=0;
608
+ hdr1.strokeAlign="INSIDE";
609
+ tbl1.appendChild(hdr1);
610
+ hdr1.layoutSizingHorizontal="FILL";
611
+
612
+ var h1a=figma.createText();h1a.fontName=F.sb;h1a.fontSize=12;
613
+ h1a.lineHeight={unit:"PIXELS",value:18};h1a.characters="Element";
614
+ h1a.fills=[{type:"SOLID",color:${C.textMain}}];
615
+ h1a.textAutoResize="HEIGHT";h1a.resize(${COL_FOCUS.element},18);
616
+ hdr1.appendChild(h1a);h1a.layoutSizingHorizontal="FIXED";
617
+
618
+ var h1b=figma.createText();h1b.fontName=F.sb;h1b.fontSize=12;
619
+ h1b.lineHeight={unit:"PIXELS",value:18};h1b.characters="Announcement";
620
+ h1b.fills=[{type:"SOLID",color:${C.textMain}}];
621
+ h1b.textAutoResize="HEIGHT";h1b.resize(${COL_FOCUS.announcement},18);
622
+ hdr1.appendChild(h1b);h1b.layoutSizingHorizontal="FIXED";
623
+
624
+ // Focus rows
625
+ var fRows=${JSON.stringify(displayFocusRows)};
626
+ for(var i=0;i<fRows.length;i++){
627
+ var r=fRows[i];
628
+ var row=figma.createFrame();
629
+ row.name="Row "+(i+1);
630
+ row.layoutMode="HORIZONTAL";
631
+ row.primaryAxisSizingMode="AUTO";
632
+ row.counterAxisSizingMode="AUTO";
633
+ row.itemSpacing=0;
634
+ row.paddingTop=10;row.paddingBottom=10;
635
+ row.paddingLeft=16;row.paddingRight=16;
636
+ row.fills=[];
637
+ row.counterAxisAlignItems="MIN";
638
+ if(i<fRows.length-1){
639
+ row.strokes=[{type:"SOLID",color:${C.border}}];
640
+ row.strokeWeight=1;
641
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
642
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
643
+ row.strokeAlign="INSIDE";
644
+ }
645
+ tbl1.appendChild(row);
646
+ row.layoutSizingHorizontal="FILL";
647
+
648
+ var c1=figma.createText();c1.fontName=F.sb;c1.fontSize=12;
649
+ c1.lineHeight={unit:"PIXELS",value:18};c1.characters=r.element;
650
+ c1.fills=[{type:"SOLID",color:${C.textMain}}];
651
+ c1.textAutoResize="HEIGHT";c1.resize(${COL_FOCUS.element},18);
652
+ row.appendChild(c1);c1.layoutSizingHorizontal="FIXED";
653
+
654
+ var c2=figma.createText();c2.fontName=F.r;c2.fontSize=12;
655
+ c2.lineHeight={unit:"PIXELS",value:18};c2.characters=r.announcement;
656
+ c2.fills=[{type:"SOLID",color:${C.textMuted}}];
657
+ c2.textAutoResize="HEIGHT";c2.resize(${COL_FOCUS.announcement},18);
658
+ row.appendChild(c2);c2.layoutSizingHorizontal="FIXED";
659
+ }
660
+
661
+ ${spacerJS(24)}
662
+
663
+ // Sub-heading: State Changes
664
+ var sh2=figma.createText();sh2.fontName=F.sb;sh2.fontSize=16;
665
+ sh2.lineHeight={unit:"PIXELS",value:24};
666
+ sh2.characters="On State Change";
667
+ sh2.fills=[{type:"SOLID",color:${C.textMain}}];
668
+ sh2.textAutoResize="HEIGHT";
669
+ m.appendChild(sh2);sh2.layoutSizingHorizontal="FILL";
670
+
671
+ ${spacerJS(8)}
672
+
673
+ // State changes table
674
+ var tbl2=figma.createFrame();
675
+ tbl2.name="State Changes";
676
+ tbl2.layoutMode="VERTICAL";
677
+ tbl2.primaryAxisSizingMode="AUTO";
678
+ tbl2.counterAxisSizingMode="AUTO";
679
+ tbl2.itemSpacing=0;
680
+ tbl2.fills=[{type:"SOLID",color:${C.bgPage}}];
681
+ tbl2.cornerRadius=8;
682
+ tbl2.strokes=[{type:"SOLID",color:${C.border}}];
683
+ tbl2.strokeWeight=1;tbl2.strokeAlign="INSIDE";
684
+ tbl2.clipsContent=true;
685
+ m.appendChild(tbl2);
686
+ tbl2.layoutSizingHorizontal="FILL";
687
+
688
+ // Header
689
+ var hdr2=figma.createFrame();
690
+ hdr2.name="Header";
691
+ hdr2.layoutMode="HORIZONTAL";
692
+ hdr2.primaryAxisSizingMode="AUTO";
693
+ hdr2.counterAxisSizingMode="AUTO";
694
+ hdr2.itemSpacing=0;
695
+ hdr2.paddingTop=12;hdr2.paddingBottom=12;
696
+ hdr2.paddingLeft=16;hdr2.paddingRight=16;
697
+ hdr2.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
698
+ hdr2.counterAxisAlignItems="MIN";
699
+ hdr2.strokes=[{type:"SOLID",color:${C.border}}];
700
+ hdr2.strokeWeight=1;
701
+ hdr2.strokeTopWeight=0;hdr2.strokeRightWeight=0;
702
+ hdr2.strokeBottomWeight=1;hdr2.strokeLeftWeight=0;
703
+ hdr2.strokeAlign="INSIDE";
704
+ tbl2.appendChild(hdr2);
705
+ hdr2.layoutSizingHorizontal="FILL";
706
+
707
+ var h2a=figma.createText();h2a.fontName=F.sb;h2a.fontSize=12;
708
+ h2a.lineHeight={unit:"PIXELS",value:18};h2a.characters="Trigger";
709
+ h2a.fills=[{type:"SOLID",color:${C.textMain}}];
710
+ h2a.textAutoResize="HEIGHT";h2a.resize(${COL_STATE.trigger},18);
711
+ hdr2.appendChild(h2a);h2a.layoutSizingHorizontal="FIXED";
712
+
713
+ var h2b=figma.createText();h2b.fontName=F.sb;h2b.fontSize=12;
714
+ h2b.lineHeight={unit:"PIXELS",value:18};h2b.characters="Behavior";
715
+ h2b.fills=[{type:"SOLID",color:${C.textMain}}];
716
+ h2b.textAutoResize="HEIGHT";h2b.resize(${COL_STATE.behavior},18);
717
+ hdr2.appendChild(h2b);h2b.layoutSizingHorizontal="FIXED";
718
+
719
+ var sRows=${JSON.stringify(stateRows)};
720
+ for(var i=0;i<sRows.length;i++){
721
+ var r=sRows[i];
722
+ var row=figma.createFrame();
723
+ row.name="Row "+(i+1);
724
+ row.layoutMode="HORIZONTAL";
725
+ row.primaryAxisSizingMode="AUTO";
726
+ row.counterAxisSizingMode="AUTO";
727
+ row.itemSpacing=0;
728
+ row.paddingTop=10;row.paddingBottom=10;
729
+ row.paddingLeft=16;row.paddingRight=16;
730
+ row.fills=[];
731
+ row.counterAxisAlignItems="MIN";
732
+ if(i<sRows.length-1){
733
+ row.strokes=[{type:"SOLID",color:${C.border}}];
734
+ row.strokeWeight=1;
735
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
736
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
737
+ row.strokeAlign="INSIDE";
738
+ }
739
+ tbl2.appendChild(row);
740
+ row.layoutSizingHorizontal="FILL";
741
+
742
+ var c1=figma.createText();c1.fontName=F.sb;c1.fontSize=12;
743
+ c1.lineHeight={unit:"PIXELS",value:18};c1.characters=r.trigger;
744
+ c1.fills=[{type:"SOLID",color:${C.textMain}}];
745
+ c1.textAutoResize="HEIGHT";c1.resize(${COL_STATE.trigger},18);
746
+ row.appendChild(c1);c1.layoutSizingHorizontal="FIXED";
747
+
748
+ var c2=figma.createText();c2.fontName=F.r;c2.fontSize=12;
749
+ c2.lineHeight={unit:"PIXELS",value:18};c2.characters=r.behavior;
750
+ c2.fills=[{type:"SOLID",color:${C.textMuted}}];
751
+ c2.textAutoResize="HEIGHT";c2.resize(${COL_STATE.behavior},18);
752
+ row.appendChild(c2);c2.layoutSizingHorizontal="FIXED";
753
+ }
754
+
755
+ ${spacerJS(16)}
756
+ ${dividerJS()}
757
+
758
+ return{ok:true};
759
+ })();
760
+ `);
761
+ }
762
+
763
+ async function renderFocusManagement(
764
+ bridge: Bridge,
765
+ mId: string,
766
+ rules: FocusRule[]
767
+ ): Promise<void> {
768
+ const ruleItems = rules.map((r) => ({
769
+ scenario: r.scenario,
770
+ rule: r.rule,
771
+ }));
772
+
773
+ await bridge.execute(`
774
+ (async () => {
775
+ ${FL}
776
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
777
+ if(!m)return{error:"no master"};
778
+
779
+ ${spacerJS(32)}
780
+ ${sectionHeadingJS("Focus Management & State Changes")}
781
+ ${spacerJS(12)}
782
+
783
+ var items=${JSON.stringify(ruleItems)};
784
+ for(var i=0;i<items.length;i++){
785
+ var item=items[i];
786
+
787
+ var card=figma.createFrame();
788
+ card.name="Focus Rule "+(i+1);
789
+ card.layoutMode="VERTICAL";
790
+ card.primaryAxisSizingMode="AUTO";
791
+ card.counterAxisSizingMode="AUTO";
792
+ card.paddingTop=12;card.paddingBottom=12;
793
+ card.paddingLeft=16;card.paddingRight=16;
794
+ card.itemSpacing=4;
795
+ card.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
796
+ card.cornerRadius=8;
797
+ m.appendChild(card);
798
+ card.layoutSizingHorizontal="FILL";
799
+
800
+ var title=figma.createText();title.fontName=F.sb;title.fontSize=13;
801
+ title.lineHeight={unit:"PIXELS",value:20};
802
+ title.characters=item.scenario;
803
+ title.fills=[{type:"SOLID",color:${C.textMain}}];
804
+ title.textAutoResize="HEIGHT";
805
+ card.appendChild(title);title.layoutSizingHorizontal="FILL";
806
+
807
+ var body=figma.createText();body.fontName=F.r;body.fontSize=13;
808
+ body.lineHeight={unit:"PIXELS",value:20};
809
+ body.characters=item.rule;
810
+ body.fills=[{type:"SOLID",color:${C.textMuted}}];
811
+ body.textAutoResize="HEIGHT";
812
+ card.appendChild(body);body.layoutSizingHorizontal="FILL";
813
+
814
+ ${spacerJS(8)}
815
+ }
816
+
817
+ ${spacerJS(16)}
818
+ ${dividerJS()}
819
+
820
+ return{ok:true};
821
+ })();
822
+ `);
823
+ }
824
+
825
+ async function renderImplementationNotes(
826
+ bridge: Bridge,
827
+ mId: string,
828
+ analysis: A11yOrderAnalysis
829
+ ): Promise<void> {
830
+ const notes = analysis.implementationNotes;
831
+
832
+ // ARIA table
833
+ const ariaRows = notes.ariaTable.map((a) => ({
834
+ element: truncate(a.element, 40),
835
+ attribute: a.attribute,
836
+ value: a.value,
837
+ }));
838
+ const displayAriaRows = ariaRows.slice(0, 25);
839
+
840
+ // KB behavior table
841
+ const kbRows = notes.keyboardBehavior.map((k) => ({
842
+ component: k.component,
843
+ key: k.key,
844
+ action: k.action,
845
+ }));
846
+
847
+ const COL_ARIA = { element: 280, attribute: 180, value: CONTENT_W - 280 - 180 - 32 };
848
+ const COL_KB = { component: 200, key: 220, action: CONTENT_W - 200 - 220 - 32 };
849
+
850
+ await bridge.execute(`
851
+ (async () => {
852
+ ${FL}
853
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
854
+ if(!m)return{error:"no master"};
855
+
856
+ ${spacerJS(32)}
857
+ ${sectionHeadingJS("Implementation Notes for Developers")}
858
+ ${spacerJS(16)}
859
+
860
+ // Sub-heading: Required ARIA
861
+ var sh1=figma.createText();sh1.fontName=F.sb;sh1.fontSize=16;
862
+ sh1.lineHeight={unit:"PIXELS",value:24};
863
+ sh1.characters="Required ARIA (only where native HTML is insufficient)";
864
+ sh1.fills=[{type:"SOLID",color:${C.textMain}}];
865
+ sh1.textAutoResize="HEIGHT";
866
+ m.appendChild(sh1);sh1.layoutSizingHorizontal="FILL";
867
+
868
+ ${spacerJS(8)}
869
+
870
+ // ARIA table
871
+ var tbl1=figma.createFrame();
872
+ tbl1.name="ARIA Table";
873
+ tbl1.layoutMode="VERTICAL";
874
+ tbl1.primaryAxisSizingMode="AUTO";
875
+ tbl1.counterAxisSizingMode="AUTO";
876
+ tbl1.itemSpacing=0;
877
+ tbl1.fills=[{type:"SOLID",color:${C.bgPage}}];
878
+ tbl1.cornerRadius=8;
879
+ tbl1.strokes=[{type:"SOLID",color:${C.border}}];
880
+ tbl1.strokeWeight=1;tbl1.strokeAlign="INSIDE";
881
+ tbl1.clipsContent=true;
882
+ m.appendChild(tbl1);
883
+ tbl1.layoutSizingHorizontal="FILL";
884
+
885
+ // Header
886
+ var hdr1=figma.createFrame();
887
+ hdr1.name="Header";
888
+ hdr1.layoutMode="HORIZONTAL";
889
+ hdr1.primaryAxisSizingMode="AUTO";
890
+ hdr1.counterAxisSizingMode="AUTO";
891
+ hdr1.itemSpacing=0;
892
+ hdr1.paddingTop=12;hdr1.paddingBottom=12;
893
+ hdr1.paddingLeft=16;hdr1.paddingRight=16;
894
+ hdr1.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
895
+ hdr1.counterAxisAlignItems="MIN";
896
+ hdr1.strokes=[{type:"SOLID",color:${C.border}}];
897
+ hdr1.strokeWeight=1;
898
+ hdr1.strokeTopWeight=0;hdr1.strokeRightWeight=0;
899
+ hdr1.strokeBottomWeight=1;hdr1.strokeLeftWeight=0;
900
+ hdr1.strokeAlign="INSIDE";
901
+ tbl1.appendChild(hdr1);
902
+ hdr1.layoutSizingHorizontal="FILL";
903
+
904
+ var h1Labels=["Element","Attribute","Value"];
905
+ var h1Widths=[${COL_ARIA.element},${COL_ARIA.attribute},${COL_ARIA.value}];
906
+ for(var c=0;c<h1Labels.length;c++){
907
+ var ht=figma.createText();ht.fontName=F.sb;ht.fontSize=12;
908
+ ht.lineHeight={unit:"PIXELS",value:18};ht.characters=h1Labels[c];
909
+ ht.fills=[{type:"SOLID",color:${C.textMain}}];
910
+ ht.textAutoResize="HEIGHT";ht.resize(h1Widths[c],18);
911
+ hdr1.appendChild(ht);ht.layoutSizingHorizontal="FIXED";
912
+ }
913
+
914
+ var aRows=${JSON.stringify(displayAriaRows)};
915
+ for(var i=0;i<aRows.length;i++){
916
+ var d=aRows[i];
917
+ var row=figma.createFrame();
918
+ row.name="Row "+(i+1);
919
+ row.layoutMode="HORIZONTAL";
920
+ row.primaryAxisSizingMode="AUTO";
921
+ row.counterAxisSizingMode="AUTO";
922
+ row.itemSpacing=0;
923
+ row.paddingTop=10;row.paddingBottom=10;
924
+ row.paddingLeft=16;row.paddingRight=16;
925
+ row.fills=[];
926
+ row.counterAxisAlignItems="MIN";
927
+ if(i<aRows.length-1){
928
+ row.strokes=[{type:"SOLID",color:${C.border}}];
929
+ row.strokeWeight=1;
930
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
931
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
932
+ row.strokeAlign="INSIDE";
933
+ }
934
+ tbl1.appendChild(row);
935
+ row.layoutSizingHorizontal="FILL";
936
+
937
+ var vals=[d.element,d.attribute,d.value];
938
+ var fonts=[F.r,F.mono,F.mono];
939
+ var colors=[${C.textMain},${C.accent},${C.textMuted}];
940
+ var ws=[${COL_ARIA.element},${COL_ARIA.attribute},${COL_ARIA.value}];
941
+ for(var c=0;c<3;c++){
942
+ var ct=figma.createText();ct.fontName=fonts[c];ct.fontSize=12;
943
+ ct.lineHeight={unit:"PIXELS",value:18};ct.characters=vals[c];
944
+ ct.fills=[{type:"SOLID",color:colors[c]}];
945
+ ct.textAutoResize="HEIGHT";ct.resize(ws[c],18);
946
+ row.appendChild(ct);ct.layoutSizingHorizontal="FIXED";
947
+ }
948
+ }
949
+
950
+ return{ok:true};
951
+ })();
952
+ `);
953
+
954
+ // Keyboard behavior table
955
+ await bridge.execute(`
956
+ (async () => {
957
+ ${FL}
958
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
959
+ if(!m)return{error:"no master"};
960
+
961
+ ${spacerJS(24)}
962
+
963
+ var sh2=figma.createText();sh2.fontName=F.sb;sh2.fontSize=16;
964
+ sh2.lineHeight={unit:"PIXELS",value:24};
965
+ sh2.characters="Keyboard Behaviour Expectations";
966
+ sh2.fills=[{type:"SOLID",color:${C.textMain}}];
967
+ sh2.textAutoResize="HEIGHT";
968
+ m.appendChild(sh2);sh2.layoutSizingHorizontal="FILL";
969
+
970
+ ${spacerJS(8)}
971
+
972
+ var tbl2=figma.createFrame();
973
+ tbl2.name="Keyboard Behavior";
974
+ tbl2.layoutMode="VERTICAL";
975
+ tbl2.primaryAxisSizingMode="AUTO";
976
+ tbl2.counterAxisSizingMode="AUTO";
977
+ tbl2.itemSpacing=0;
978
+ tbl2.fills=[{type:"SOLID",color:${C.bgPage}}];
979
+ tbl2.cornerRadius=8;
980
+ tbl2.strokes=[{type:"SOLID",color:${C.border}}];
981
+ tbl2.strokeWeight=1;tbl2.strokeAlign="INSIDE";
982
+ tbl2.clipsContent=true;
983
+ m.appendChild(tbl2);
984
+ tbl2.layoutSizingHorizontal="FILL";
985
+
986
+ var hdr2=figma.createFrame();
987
+ hdr2.name="Header";
988
+ hdr2.layoutMode="HORIZONTAL";
989
+ hdr2.primaryAxisSizingMode="AUTO";
990
+ hdr2.counterAxisSizingMode="AUTO";
991
+ hdr2.itemSpacing=0;
992
+ hdr2.paddingTop=12;hdr2.paddingBottom=12;
993
+ hdr2.paddingLeft=16;hdr2.paddingRight=16;
994
+ hdr2.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
995
+ hdr2.counterAxisAlignItems="MIN";
996
+ hdr2.strokes=[{type:"SOLID",color:${C.border}}];
997
+ hdr2.strokeWeight=1;
998
+ hdr2.strokeTopWeight=0;hdr2.strokeRightWeight=0;
999
+ hdr2.strokeBottomWeight=1;hdr2.strokeLeftWeight=0;
1000
+ hdr2.strokeAlign="INSIDE";
1001
+ tbl2.appendChild(hdr2);
1002
+ hdr2.layoutSizingHorizontal="FILL";
1003
+
1004
+ var h2Labels=["Component","Key","Action"];
1005
+ var h2Widths=[${COL_KB.component},${COL_KB.key},${COL_KB.action}];
1006
+ for(var c=0;c<h2Labels.length;c++){
1007
+ var ht=figma.createText();ht.fontName=F.sb;ht.fontSize=12;
1008
+ ht.lineHeight={unit:"PIXELS",value:18};ht.characters=h2Labels[c];
1009
+ ht.fills=[{type:"SOLID",color:${C.textMain}}];
1010
+ ht.textAutoResize="HEIGHT";ht.resize(h2Widths[c],18);
1011
+ hdr2.appendChild(ht);ht.layoutSizingHorizontal="FIXED";
1012
+ }
1013
+
1014
+ var kRows=${JSON.stringify(kbRows)};
1015
+ for(var i=0;i<kRows.length;i++){
1016
+ var d=kRows[i];
1017
+ var row=figma.createFrame();
1018
+ row.name="Row "+(i+1);
1019
+ row.layoutMode="HORIZONTAL";
1020
+ row.primaryAxisSizingMode="AUTO";
1021
+ row.counterAxisSizingMode="AUTO";
1022
+ row.itemSpacing=0;
1023
+ row.paddingTop=10;row.paddingBottom=10;
1024
+ row.paddingLeft=16;row.paddingRight=16;
1025
+ row.fills=[];
1026
+ row.counterAxisAlignItems="MIN";
1027
+ if(i<kRows.length-1){
1028
+ row.strokes=[{type:"SOLID",color:${C.border}}];
1029
+ row.strokeWeight=1;
1030
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
1031
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
1032
+ row.strokeAlign="INSIDE";
1033
+ }
1034
+ tbl2.appendChild(row);
1035
+ row.layoutSizingHorizontal="FILL";
1036
+
1037
+ var vals=[d.component,d.key,d.action];
1038
+ var fonts=[F.r,F.mono,F.r];
1039
+ var colors=[${C.textMain},${C.accent},${C.textMuted}];
1040
+ var ws=[${COL_KB.component},${COL_KB.key},${COL_KB.action}];
1041
+ for(var c=0;c<3;c++){
1042
+ var ct=figma.createText();ct.fontName=fonts[c];ct.fontSize=12;
1043
+ ct.lineHeight={unit:"PIXELS",value:18};ct.characters=vals[c];
1044
+ ct.fills=[{type:"SOLID",color:colors[c]}];
1045
+ ct.textAutoResize="HEIGHT";ct.resize(ws[c],18);
1046
+ row.appendChild(ct);ct.layoutSizingHorizontal="FIXED";
1047
+ }
1048
+ }
1049
+
1050
+ return{ok:true};
1051
+ })();
1052
+ `);
1053
+
1054
+ // Do/Don't rules
1055
+ const doRules = notes.dosDonts.filter((r) => r.startsWith("Do:"));
1056
+ const dontRules = notes.dosDonts.filter((r) => r.startsWith("Don't:"));
1057
+
1058
+ await bridge.execute(`
1059
+ (async () => {
1060
+ ${FL}
1061
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
1062
+ if(!m)return{error:"no master"};
1063
+
1064
+ ${spacerJS(24)}
1065
+
1066
+ var sh3=figma.createText();sh3.fontName=F.sb;sh3.fontSize=16;
1067
+ sh3.lineHeight={unit:"PIXELS",value:24};
1068
+ sh3.characters="Do / Don't Rules";
1069
+ sh3.fills=[{type:"SOLID",color:${C.textMain}}];
1070
+ sh3.textAutoResize="HEIGHT";
1071
+ m.appendChild(sh3);sh3.layoutSizingHorizontal="FILL";
1072
+
1073
+ ${spacerJS(8)}
1074
+
1075
+ // Two-column layout
1076
+ var cols=figma.createFrame();
1077
+ cols.name="Do Dont Columns";
1078
+ cols.layoutMode="HORIZONTAL";
1079
+ cols.primaryAxisSizingMode="AUTO";
1080
+ cols.counterAxisSizingMode="AUTO";
1081
+ cols.itemSpacing=16;
1082
+ cols.fills=[];
1083
+ m.appendChild(cols);
1084
+ cols.layoutSizingHorizontal="FILL";
1085
+
1086
+ // Do column
1087
+ var doCol=figma.createFrame();
1088
+ doCol.name="Do";
1089
+ doCol.layoutMode="VERTICAL";
1090
+ doCol.primaryAxisSizingMode="AUTO";
1091
+ doCol.counterAxisSizingMode="AUTO";
1092
+ doCol.paddingTop=16;doCol.paddingBottom=16;
1093
+ doCol.paddingLeft=16;doCol.paddingRight=16;
1094
+ doCol.itemSpacing=8;
1095
+ doCol.cornerRadius=8;
1096
+ doCol.fills=[{type:"SOLID",color:${C.greenBg}}];
1097
+ cols.appendChild(doCol);
1098
+ doCol.layoutSizingHorizontal="FILL";
1099
+
1100
+ var doTitle=figma.createText();doTitle.fontName=F.sb;doTitle.fontSize=14;
1101
+ doTitle.characters="\\u2705 Do";
1102
+ doTitle.fills=[{type:"SOLID",color:${C.green}}];
1103
+ doCol.appendChild(doTitle);doTitle.layoutSizingHorizontal="FILL";
1104
+
1105
+ var doRules=${JSON.stringify(doRules)};
1106
+ for(var i=0;i<doRules.length;i++){
1107
+ var dt=figma.createText();dt.fontName=F.r;dt.fontSize=12;
1108
+ dt.lineHeight={unit:"PIXELS",value:18};
1109
+ dt.characters=doRules[i].replace(/^Do: /,"\\u2022 ");
1110
+ dt.fills=[{type:"SOLID",color:${C.textMain}}];
1111
+ dt.textAutoResize="HEIGHT";
1112
+ doCol.appendChild(dt);dt.layoutSizingHorizontal="FILL";
1113
+ }
1114
+
1115
+ // Don't column
1116
+ var dontCol=figma.createFrame();
1117
+ dontCol.name="Don't";
1118
+ dontCol.layoutMode="VERTICAL";
1119
+ dontCol.primaryAxisSizingMode="AUTO";
1120
+ dontCol.counterAxisSizingMode="AUTO";
1121
+ dontCol.paddingTop=16;dontCol.paddingBottom=16;
1122
+ dontCol.paddingLeft=16;dontCol.paddingRight=16;
1123
+ dontCol.itemSpacing=8;
1124
+ dontCol.cornerRadius=8;
1125
+ dontCol.fills=[{type:"SOLID",color:${C.warnBg}}];
1126
+ cols.appendChild(dontCol);
1127
+ dontCol.layoutSizingHorizontal="FILL";
1128
+
1129
+ var dontTitle=figma.createText();dontTitle.fontName=F.sb;dontTitle.fontSize=14;
1130
+ dontTitle.characters="\\u274c Don't";
1131
+ dontTitle.fills=[{type:"SOLID",color:${C.warnBorder}}];
1132
+ dontCol.appendChild(dontTitle);dontTitle.layoutSizingHorizontal="FILL";
1133
+
1134
+ var dontRules=${JSON.stringify(dontRules)};
1135
+ for(var i=0;i<dontRules.length;i++){
1136
+ var dt=figma.createText();dt.fontName=F.r;dt.fontSize=12;
1137
+ dt.lineHeight={unit:"PIXELS",value:18};
1138
+ dt.characters=dontRules[i].replace(/^Don't: /,"\\u2022 ");
1139
+ dt.fills=[{type:"SOLID",color:${C.textMain}}];
1140
+ dt.textAutoResize="HEIGHT";
1141
+ dontCol.appendChild(dt);dt.layoutSizingHorizontal="FILL";
1142
+ }
1143
+
1144
+ ${spacerJS(16)}
1145
+ ${dividerJS()}
1146
+
1147
+ return{ok:true};
1148
+ })();
1149
+ `);
1150
+ }
1151
+
1152
+ async function renderWarnings(
1153
+ bridge: Bridge,
1154
+ mId: string,
1155
+ warnings: Warning[]
1156
+ ): Promise<void> {
1157
+ if (warnings.length === 0) return;
1158
+
1159
+ const warningData = warnings.map((w) => ({
1160
+ id: w.id,
1161
+ severity: w.severity,
1162
+ title: w.title,
1163
+ description: w.description,
1164
+ }));
1165
+
1166
+ await bridge.execute(`
1167
+ (async () => {
1168
+ ${FL}
1169
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
1170
+ if(!m)return{error:"no master"};
1171
+
1172
+ ${spacerJS(32)}
1173
+ ${sectionHeadingJS("Warnings")}
1174
+ ${spacerJS(12)}
1175
+
1176
+ var warnings=${JSON.stringify(warningData)};
1177
+ var sevColors={
1178
+ "Critical":{bg:${C.warnBg},border:${C.warnBorder},text:${C.warnBorder}},
1179
+ "Warning":{bg:${C.warnAmberBg},border:${C.warnAmberBdr},text:${C.warnAmberBdr}},
1180
+ "Info":{bg:${C.infoBg},border:${C.infoBorder},text:${C.infoBorder}}
1181
+ };
1182
+
1183
+ for(var i=0;i<warnings.length;i++){
1184
+ var w=warnings[i];
1185
+ var sc=sevColors[w.severity]||sevColors["Info"];
1186
+
1187
+ var card=figma.createFrame();
1188
+ card.name="Warning "+(i+1);
1189
+ card.layoutMode="VERTICAL";
1190
+ card.primaryAxisSizingMode="AUTO";
1191
+ card.counterAxisSizingMode="AUTO";
1192
+ card.paddingTop=16;card.paddingBottom=16;
1193
+ card.paddingLeft=20;card.paddingRight=16;
1194
+ card.itemSpacing=6;
1195
+ card.cornerRadius=8;
1196
+ card.fills=[{type:"SOLID",color:sc.bg}];
1197
+ card.strokes=[{type:"SOLID",color:sc.border}];
1198
+ card.strokeWeight=2;
1199
+ card.strokeLeftWeight=4;
1200
+ card.strokeAlign="INSIDE";
1201
+ m.appendChild(card);
1202
+ card.layoutSizingHorizontal="FILL";
1203
+
1204
+ // Severity + Title
1205
+ var title=figma.createText();title.fontName=F.sb;title.fontSize=14;
1206
+ title.lineHeight={unit:"PIXELS",value:22};
1207
+ title.characters=w.id+". ["+w.severity+"] "+w.title;
1208
+ title.fills=[{type:"SOLID",color:sc.text}];
1209
+ title.textAutoResize="HEIGHT";
1210
+ card.appendChild(title);title.layoutSizingHorizontal="FILL";
1211
+
1212
+ // Description
1213
+ var desc=figma.createText();desc.fontName=F.r;desc.fontSize=13;
1214
+ desc.lineHeight={unit:"PIXELS",value:20};
1215
+ desc.characters=w.description;
1216
+ desc.fills=[{type:"SOLID",color:${C.textMain}}];
1217
+ desc.textAutoResize="HEIGHT";
1218
+ card.appendChild(desc);desc.layoutSizingHorizontal="FILL";
1219
+
1220
+ ${spacerJS(8)}
1221
+ }
1222
+
1223
+ ${spacerJS(16)}
1224
+ ${dividerJS()}
1225
+
1226
+ return{ok:true};
1227
+ })();
1228
+ `);
1229
+ }
1230
+
1231
+ async function renderAuditSummary(
1232
+ bridge: Bridge,
1233
+ mId: string,
1234
+ summary: AuditSummaryRow[]
1235
+ ): Promise<void> {
1236
+ const COL_SUM = { severity: 120, count: 80, category: CONTENT_W - 120 - 80 - 32 };
1237
+
1238
+ await bridge.execute(`
1239
+ (async () => {
1240
+ ${FL}
1241
+ var m=await figma.getNodeByIdAsync(${esc(mId)});
1242
+ if(!m)return{error:"no master"};
1243
+
1244
+ ${spacerJS(32)}
1245
+ ${sectionHeadingJS("A11y Audit Summary")}
1246
+ ${spacerJS(12)}
1247
+
1248
+ var tbl=figma.createFrame();
1249
+ tbl.name="Audit Summary";
1250
+ tbl.layoutMode="VERTICAL";
1251
+ tbl.primaryAxisSizingMode="AUTO";
1252
+ tbl.counterAxisSizingMode="AUTO";
1253
+ tbl.itemSpacing=0;
1254
+ tbl.fills=[{type:"SOLID",color:${C.bgPage}}];
1255
+ tbl.cornerRadius=8;
1256
+ tbl.strokes=[{type:"SOLID",color:${C.border}}];
1257
+ tbl.strokeWeight=1;tbl.strokeAlign="INSIDE";
1258
+ tbl.clipsContent=true;
1259
+ m.appendChild(tbl);
1260
+ tbl.layoutSizingHorizontal="FILL";
1261
+
1262
+ // Header
1263
+ var hdr=figma.createFrame();
1264
+ hdr.name="Header";
1265
+ hdr.layoutMode="HORIZONTAL";
1266
+ hdr.primaryAxisSizingMode="AUTO";
1267
+ hdr.counterAxisSizingMode="AUTO";
1268
+ hdr.itemSpacing=0;
1269
+ hdr.paddingTop=12;hdr.paddingBottom=12;
1270
+ hdr.paddingLeft=16;hdr.paddingRight=16;
1271
+ hdr.fills=[{type:"SOLID",color:${C.bgTableHeader}}];
1272
+ hdr.counterAxisAlignItems="MIN";
1273
+ hdr.strokes=[{type:"SOLID",color:${C.border}}];
1274
+ hdr.strokeWeight=1;
1275
+ hdr.strokeTopWeight=0;hdr.strokeRightWeight=0;
1276
+ hdr.strokeBottomWeight=1;hdr.strokeLeftWeight=0;
1277
+ hdr.strokeAlign="INSIDE";
1278
+ tbl.appendChild(hdr);
1279
+ hdr.layoutSizingHorizontal="FILL";
1280
+
1281
+ var hLabels=["Severity","Count","Category"];
1282
+ var hWidths=[${COL_SUM.severity},${COL_SUM.count},${COL_SUM.category}];
1283
+ for(var c=0;c<hLabels.length;c++){
1284
+ var ht=figma.createText();ht.fontName=F.sb;ht.fontSize=12;
1285
+ ht.lineHeight={unit:"PIXELS",value:18};ht.characters=hLabels[c];
1286
+ ht.fills=[{type:"SOLID",color:${C.textMain}}];
1287
+ ht.textAutoResize="HEIGHT";ht.resize(hWidths[c],18);
1288
+ hdr.appendChild(ht);ht.layoutSizingHorizontal="FIXED";
1289
+ }
1290
+
1291
+ var sevColorMap={
1292
+ "Error":${C.warnBorder},
1293
+ "Warning":${C.warnAmberBdr},
1294
+ "Suggestion":${C.accent},
1295
+ "Total":${C.textMain}
1296
+ };
1297
+
1298
+ var rows=${JSON.stringify(summary)};
1299
+ for(var i=0;i<rows.length;i++){
1300
+ var d=rows[i];
1301
+ var row=figma.createFrame();
1302
+ row.name="Row "+(i+1);
1303
+ row.layoutMode="HORIZONTAL";
1304
+ row.primaryAxisSizingMode="AUTO";
1305
+ row.counterAxisSizingMode="AUTO";
1306
+ row.itemSpacing=0;
1307
+ row.paddingTop=10;row.paddingBottom=10;
1308
+ row.paddingLeft=16;row.paddingRight=16;
1309
+ row.fills=[];
1310
+ row.counterAxisAlignItems="MIN";
1311
+ if(i<rows.length-1){
1312
+ row.strokes=[{type:"SOLID",color:${C.border}}];
1313
+ row.strokeWeight=1;
1314
+ row.strokeTopWeight=0;row.strokeRightWeight=0;
1315
+ row.strokeBottomWeight=1;row.strokeLeftWeight=0;
1316
+ row.strokeAlign="INSIDE";
1317
+ }
1318
+ tbl.appendChild(row);
1319
+ row.layoutSizingHorizontal="FILL";
1320
+
1321
+ var sc=sevColorMap[d.severity]||${C.textMain};
1322
+ var isTotal=d.severity==="Total";
1323
+
1324
+ var c0=figma.createText();c0.fontName=isTotal?F.b:F.sb;c0.fontSize=12;
1325
+ c0.lineHeight={unit:"PIXELS",value:18};c0.characters=d.severity;
1326
+ c0.fills=[{type:"SOLID",color:sc}];
1327
+ c0.textAutoResize="HEIGHT";c0.resize(${COL_SUM.severity},18);
1328
+ row.appendChild(c0);c0.layoutSizingHorizontal="FIXED";
1329
+
1330
+ var c1=figma.createText();c1.fontName=isTotal?F.b:F.sb;c1.fontSize=12;
1331
+ c1.lineHeight={unit:"PIXELS",value:18};c1.characters=String(d.count);
1332
+ c1.fills=[{type:"SOLID",color:sc}];
1333
+ c1.textAutoResize="HEIGHT";c1.resize(${COL_SUM.count},18);
1334
+ row.appendChild(c1);c1.layoutSizingHorizontal="FIXED";
1335
+
1336
+ var c2=figma.createText();c2.fontName=F.r;c2.fontSize=12;
1337
+ c2.lineHeight={unit:"PIXELS",value:18};c2.characters=d.category;
1338
+ c2.fills=[{type:"SOLID",color:${C.textMuted}}];
1339
+ c2.textAutoResize="HEIGHT";c2.resize(${COL_SUM.category},18);
1340
+ row.appendChild(c2);c2.layoutSizingHorizontal="FIXED";
1341
+ }
1342
+
1343
+ return{ok:true};
1344
+ })();
1345
+ `);
1346
+ }