@pixel-point/toolcraft 0.0.17 → 0.0.19

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 (503) hide show
  1. package/package.json +1 -1
  2. package/src/generate-demand-only-lifecycle.test.mjs +9 -1
  3. package/src/generate-performance-iteration-execution.test.mjs +3 -3
  4. package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
  5. package/src/generate-test-demand-only-lifecycle.mjs +34 -36
  6. package/src/generate-test-dependency-sandbox.mjs +4 -1
  7. package/src/generate-test-doc-assertions.mjs +81 -89
  8. package/src/generate-test-doc-assertions.test.mjs +44 -1
  9. package/src/generate-test-doc-policy-assertions.mjs +92 -0
  10. package/src/generate-test-export-doc-assertions.mjs +53 -0
  11. package/src/generate-test-file-assertions.mjs +77 -83
  12. package/src/generate-test-integrity-assertions.mjs +5 -2
  13. package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
  14. package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
  15. package/src/generate-test-package-assertions.mjs +4 -0
  16. package/src/generate-test-product-fixture.mjs +1 -1
  17. package/src/generate-test-product-fixture.test.mjs +35 -38
  18. package/src/generate-test-product-iteration.mjs +0 -1
  19. package/src/generate-test-product-iteration.test.mjs +17 -1
  20. package/src/generate-test-runtime-boundary-assertions.mjs +178 -0
  21. package/src/generate-test-standalone-assertions.mjs +7 -13
  22. package/src/generate-test-standalone-delivery-stages.mjs +2 -86
  23. package/src/generate.test.mjs +4 -0
  24. package/src/generated-integrity-manifest.test.mjs +5 -2
  25. package/src/generated-source-policy.test.mjs +0 -4
  26. package/src/package-json.mjs +5 -0
  27. package/src/package-json.test.mjs +21 -0
  28. package/src/package-manager.mjs +2 -0
  29. package/src/package-manager.test.mjs +8 -0
  30. package/src/packaged-template-fallback-helpers.mjs +254 -0
  31. package/src/packaged-template-fallback.test.mjs +121 -46
  32. package/src/packaged-template-runtime-assertions.mjs +150 -0
  33. package/templates/runtime/contracts/component-contracts.choices.test.ts +64 -5
  34. package/templates/runtime/contracts/component-contracts.choices.ts +55 -5
  35. package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
  36. package/templates/runtime/contracts/component-contracts.inputs.ts +8 -7
  37. package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
  38. package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
  39. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +22 -8
  40. package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
  41. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +3 -0
  42. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
  43. package/templates/runtime/contracts/component-contracts.runtime.ts +19 -12
  44. package/templates/runtime/contracts/component-contracts.test.ts +2 -0
  45. package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
  46. package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
  47. package/templates/runtime/contracts/decision-contracts.test.ts +35 -11
  48. package/templates/runtime/contracts/decision-contracts.ts +12 -12
  49. package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
  50. package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
  51. package/templates/runtime/export/artifact-download.ts +1 -0
  52. package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
  53. package/templates/runtime/export/artifact-frame-state.ts +16 -0
  54. package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
  55. package/templates/runtime/export/artifact-scene-frame.ts +3 -3
  56. package/templates/runtime/export/export-background.ts +0 -19
  57. package/templates/runtime/export/export-error.ts +5 -0
  58. package/templates/runtime/export/export-renderer-coverage.ts +54 -0
  59. package/templates/runtime/export/export.test.ts +45 -42
  60. package/templates/runtime/export/image-artifact-export.ts +2 -2
  61. package/templates/runtime/export/index.ts +57 -16
  62. package/templates/runtime/export/product-export-renderer.test.ts +38 -4
  63. package/templates/runtime/export/product-export-renderer.ts +0 -41
  64. package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
  65. package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
  66. package/templates/runtime/export/svg-artifact-export.ts +120 -0
  67. package/templates/runtime/export/svg-document.test.ts +221 -0
  68. package/templates/runtime/export/svg-document.ts +400 -0
  69. package/templates/runtime/export/svg-policy.ts +47 -0
  70. package/templates/runtime/index.ts +3 -0
  71. package/templates/runtime/model-import/model-import-limits.ts +15 -4
  72. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +21 -1
  73. package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
  74. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +75 -1
  75. package/templates/runtime/react/app-shell/toolcraft-app.tsx +24 -9
  76. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
  77. package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
  78. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +77 -1
  79. package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
  80. package/templates/runtime/react/canvas/canvas-shell.tsx +32 -6
  81. package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
  82. package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
  83. package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
  84. package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
  85. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
  86. package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
  87. package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
  88. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
  89. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
  90. package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
  91. package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
  92. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +40 -1
  93. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
  94. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +59 -0
  95. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
  96. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
  97. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +4 -6
  98. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +41 -6
  99. package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
  100. package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
  101. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +41 -10
  102. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +7 -4
  103. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
  104. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
  105. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
  106. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
  107. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
  108. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
  109. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
  110. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
  111. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
  112. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
  113. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
  114. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
  115. package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
  116. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
  117. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
  118. package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
  119. package/templates/runtime/react/index.ts +4 -0
  120. package/templates/runtime/react/model-rendering/model-export.ts +1 -1
  121. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
  122. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
  123. package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
  124. package/templates/runtime/scene/scene-bounds.test.ts +23 -0
  125. package/templates/runtime/scene/scene-bounds.ts +31 -17
  126. package/templates/runtime/schema/app-capabilities.test.ts +4 -0
  127. package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
  128. package/templates/runtime/schema/artifact-export-actions.ts +49 -0
  129. package/templates/runtime/schema/collection-item-controls.ts +29 -0
  130. package/templates/runtime/schema/control-applicability.test.ts +127 -0
  131. package/templates/runtime/schema/control-applicability.ts +433 -0
  132. package/templates/runtime/schema/control-schema-normalization.ts +177 -11
  133. package/templates/runtime/schema/controls-panel-actions.ts +2 -2
  134. package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
  135. package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +59 -0
  136. package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
  137. package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
  138. package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
  139. package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
  140. package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
  141. package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
  142. package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
  143. package/templates/runtime/schema/runtime-setup-section.ts +24 -5
  144. package/templates/runtime/schema/types.ts +69 -13
  145. package/templates/runtime/state/canvas-background-state.ts +1 -16
  146. package/templates/runtime/state/canvas-state.ts +32 -20
  147. package/templates/runtime/state/control-value-codecs.test.ts +98 -0
  148. package/templates/runtime/state/control-value-codecs.ts +700 -0
  149. package/templates/runtime/state/control-value-normalization.test.ts +1 -1
  150. package/templates/runtime/state/control-value-normalization.ts +127 -135
  151. package/templates/runtime/state/controls-reducer.ts +26 -3
  152. package/templates/runtime/state/create-template-state.test.ts +30 -0
  153. package/templates/runtime/state/create-template-state.ts +52 -31
  154. package/templates/runtime/state/orientation-pose.ts +80 -0
  155. package/templates/runtime/state/persistence-control-values.test.ts +59 -0
  156. package/templates/runtime/state/reducer-controls.test.ts +45 -0
  157. package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
  158. package/templates/runtime/state/reducer-timeline.test.ts +70 -0
  159. package/templates/runtime/state/timeline-reducer.ts +40 -2
  160. package/templates/runtime/testing/performance-schema-queries.ts +2 -2
  161. package/templates/starter/AGENTS.md +29 -28
  162. package/templates/starter/docs/toolcraft/README.md +6 -6
  163. package/templates/starter/docs/toolcraft/acceptance-testing.md +34 -48
  164. package/templates/starter/docs/toolcraft/agent-worklog.md +103 -1
  165. package/templates/starter/docs/toolcraft/assembly-workflow.md +16 -8
  166. package/templates/starter/docs/toolcraft/component-rules.md +9 -7
  167. package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
  168. package/templates/starter/docs/toolcraft/core/layout.md +13 -8
  169. package/templates/starter/docs/toolcraft/core/media-upload.md +3 -1
  170. package/templates/starter/docs/toolcraft/core/performance.md +8 -10
  171. package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
  172. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +15 -3
  173. package/templates/starter/docs/toolcraft/core/setup-export.md +67 -11
  174. package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
  175. package/templates/starter/docs/toolcraft/decision-contract.md +4 -2
  176. package/templates/starter/docs/toolcraft/performance.md +8 -10
  177. package/templates/starter/docs/toolcraft/renderer-technique.md +6 -2
  178. package/templates/starter/docs/toolcraft/schema-reference.md +24 -22
  179. package/templates/starter/docs/toolcraft/workflow.md +14 -14
  180. package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
  181. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +45 -2
  182. package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
  183. package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
  184. package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
  185. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +63 -33
  186. package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
  187. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -15
  188. package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
  189. package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
  190. package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +20 -11
  191. package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
  192. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
  193. package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
  194. package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
  195. package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
  196. package/templates/starter/e2e/browser-proof-session.ts +43 -15
  197. package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
  198. package/templates/starter/e2e/browser-proof-types.ts +15 -0
  199. package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
  200. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +9 -2
  201. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +51 -32
  202. package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
  203. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +122 -0
  204. package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
  205. package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
  206. package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
  207. package/templates/starter/e2e/product-observable-helpers.ts +8 -129
  208. package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
  209. package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
  210. package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
  211. package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
  212. package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
  213. package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
  214. package/templates/starter/package.json +2 -0
  215. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  216. package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
  217. package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
  218. package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
  219. package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
  220. package/templates/starter/scripts/run-browser-performance.mjs +0 -6
  221. package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
  222. package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
  223. package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
  224. package/templates/starter/scripts/run-feature-verification.mjs +212 -0
  225. package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
  226. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
  227. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
  228. package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
  229. package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
  230. package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
  231. package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
  232. package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
  233. package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
  234. package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
  235. package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
  236. package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
  237. package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
  238. package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
  239. package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
  240. package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
  241. package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
  242. package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
  243. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
  244. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
  245. package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
  246. package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
  247. package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
  248. package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
  249. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
  250. package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
  251. package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
  252. package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
  253. package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
  254. package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
  255. package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
  256. package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
  257. package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
  258. package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
  259. package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
  260. package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
  261. package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
  262. package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
  263. package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
  264. package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
  265. package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
  266. package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
  267. package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
  268. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
  269. package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
  270. package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
  271. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
  272. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
  273. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
  274. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
  275. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
  276. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
  277. package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
  278. package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
  279. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
  280. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
  281. package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
  282. package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
  283. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
  284. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
  285. package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
  286. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
  287. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
  288. package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
  289. package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
  290. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
  291. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
  292. package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
  293. package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
  294. package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
  295. package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
  296. package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
  297. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
  298. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
  299. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
  300. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
  301. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
  302. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
  303. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
  304. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
  305. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
  306. package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
  307. package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
  308. package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
  309. package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
  310. package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
  311. package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
  312. package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
  313. package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
  314. package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
  315. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
  316. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
  317. package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
  318. package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
  319. package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
  320. package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
  321. package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
  322. package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
  323. package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
  324. package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
  325. package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
  326. package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
  327. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +85 -115
  328. package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
  329. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -72
  330. package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
  331. package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
  332. package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
  333. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +16 -18
  334. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +200 -0
  335. package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
  336. package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
  337. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
  338. package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
  339. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
  340. package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
  341. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
  342. package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
  343. package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
  344. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +2 -0
  345. package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
  346. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
  347. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
  348. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
  349. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
  350. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
  351. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
  352. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
  353. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
  354. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +161 -0
  355. package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
  356. package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
  357. package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
  358. package/templates/starter/src/app/acceptance/conditions.ts +1 -1
  359. package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
  360. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -31
  361. package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
  362. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +4 -16
  363. package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
  364. package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
  365. package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
  366. package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
  367. package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
  368. package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
  369. package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
  370. package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
  371. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +21 -10
  372. package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
  373. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
  374. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
  375. package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
  376. package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
  377. package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
  378. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
  379. package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
  380. package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
  381. package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
  382. package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
  383. package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
  384. package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
  385. package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
  386. package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
  387. package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
  388. package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
  389. package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
  390. package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
  391. package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
  392. package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
  393. package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
  394. package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
  395. package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
  396. package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
  397. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
  398. package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
  399. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +22 -10
  400. package/templates/starter/src/app/acceptance/output-export-model.ts +58 -11
  401. package/templates/starter/src/app/acceptance/output-export.ts +25 -10
  402. package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
  403. package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
  404. package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
  405. package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
  406. package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
  407. package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
  408. package/templates/starter/src/app/acceptance/types.ts +65 -125
  409. package/templates/starter/src/app/acceptance/validate-coverage.ts +33 -5
  410. package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
  411. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
  412. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +312 -0
  413. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +35 -0
  414. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +18 -1
  415. package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
  416. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +66 -1
  417. package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
  418. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +113 -16
  419. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +225 -0
  420. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
  421. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
  422. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
  423. package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
  424. package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
  425. package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
  426. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
  427. package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
  428. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
  429. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +26 -0
  430. package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +39 -9
  431. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +31 -3
  432. package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
  433. package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
  434. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +56 -0
  435. package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
  436. package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
  437. package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
  438. package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
  439. package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
  440. package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
  441. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +458 -0
  442. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +4 -0
  443. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +116 -104
  444. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +29 -0
  445. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
  446. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
  447. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
  448. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
  449. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +3 -1
  450. package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
  451. package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
  452. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
  453. package/templates/starter/src/app/starter-acceptance.ts +45 -10
  454. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +338 -0
  455. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
  456. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +12 -0
  457. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
  458. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
  459. package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
  460. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
  461. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +5 -2
  462. package/templates/starter/src/routes/index.tsx +1 -0
  463. package/templates/starter/tsconfig.json +1 -0
  464. package/templates/ui/components/composites/tabs.tsx +2 -2
  465. package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
  466. package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
  467. package/templates/ui/components/controls/collection-actions/index.ts +2 -0
  468. package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
  469. package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
  470. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
  471. package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
  472. package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
  473. package/templates/ui/components/controls/file-drop/index.ts +1 -0
  474. package/templates/ui/components/controls/index.ts +3 -0
  475. package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
  476. package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
  477. package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
  478. package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
  479. package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
  480. package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
  481. package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
  482. package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
  483. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
  484. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
  485. package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
  486. package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
  487. package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
  488. package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
  489. package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
  490. package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
  491. package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
  492. package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
  493. package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
  494. package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
  495. package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
  496. package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
  497. package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
  498. package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
  499. package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
  500. package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
  501. package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
  502. package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
  503. package/templates/starter/src/app/starter-verification-impact.json +0 -15
@@ -0,0 +1,400 @@
1
+ import type { ToolcraftExportFrame } from "./export-frame";
2
+ import { ToolcraftArtifactExportError } from "./export-error";
3
+ import {
4
+ TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS,
5
+ TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE,
6
+ TOOLCRAFT_SVG_NAMESPACE,
7
+ TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS,
8
+ TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE,
9
+ TOOLCRAFT_SVG_VECTOR_PRIMITIVES,
10
+ } from "./svg-policy";
11
+
12
+ const forbiddenElementNames = new Set<string>(
13
+ TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS,
14
+ );
15
+ const vectorPrimitiveNames = new Set<string>(
16
+ TOOLCRAFT_SVG_VECTOR_PRIMITIVES,
17
+ );
18
+ const nonRenderingContainerNames = new Set<string>(
19
+ TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS,
20
+ );
21
+
22
+ type ToolcraftSvgDocument = Readonly<{ document: XMLDocument }>;
23
+ type ToolcraftSvgProductContainer = Readonly<{ container: SVGGElement }>;
24
+
25
+ export type ToolcraftSerializedSvgDocument = Readonly<{
26
+ source: string;
27
+ vectorElementCount: number;
28
+ }>;
29
+
30
+ function getDocumentImplementation(): DOMImplementation {
31
+ if (typeof document === "undefined") {
32
+ throw new ToolcraftArtifactExportError({
33
+ code: "svg-document-invalid",
34
+ message: "SVG export requires browser XML document support.",
35
+ });
36
+ }
37
+ return document.implementation;
38
+ }
39
+
40
+ function createSvgXmlDocument(rootName: "g" | "svg"): XMLDocument {
41
+ return getDocumentImplementation().createDocument(
42
+ TOOLCRAFT_SVG_NAMESPACE,
43
+ rootName,
44
+ null,
45
+ );
46
+ }
47
+
48
+ function setFrameAttributes(
49
+ root: SVGSVGElement,
50
+ frame: ToolcraftExportFrame,
51
+ ): void {
52
+ root.setAttribute("width", String(frame.width));
53
+ root.setAttribute("height", String(frame.height));
54
+ root.setAttribute(
55
+ "viewBox",
56
+ `${frame.x} ${frame.y} ${frame.width} ${frame.height}`,
57
+ );
58
+ }
59
+
60
+ export function createToolcraftSvgDocument(
61
+ frame: ToolcraftExportFrame,
62
+ ): ToolcraftSvgDocument {
63
+ const svgDocument = createSvgXmlDocument("svg");
64
+ const root = svgDocument.querySelector("svg");
65
+ if (!root) {
66
+ throw new ToolcraftArtifactExportError({
67
+ code: "svg-document-invalid",
68
+ message: "Runtime could not create the SVG document root.",
69
+ });
70
+ }
71
+ setFrameAttributes(root, frame);
72
+ return Object.freeze({ document: svgDocument });
73
+ }
74
+
75
+ export function createToolcraftSvgProductContainer(): ToolcraftSvgProductContainer {
76
+ const productDocument = createSvgXmlDocument("g");
77
+ const container = productDocument.querySelector("g");
78
+ if (!container) {
79
+ throw new ToolcraftArtifactExportError({
80
+ code: "svg-document-invalid",
81
+ message: "Runtime could not create the SVG product container.",
82
+ });
83
+ }
84
+ container.setAttribute(TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE, "true");
85
+ return Object.freeze({ container });
86
+ }
87
+
88
+ function hasNonRenderingAncestor(
89
+ element: Element,
90
+ container: Element,
91
+ ): boolean {
92
+ let current = element.parentElement;
93
+ while (current && !current.isSameNode(container)) {
94
+ if (nonRenderingContainerNames.has(current.localName.toLowerCase())) {
95
+ return true;
96
+ }
97
+ current = current.parentElement;
98
+ }
99
+ return false;
100
+ }
101
+
102
+ function validateUrlReferences(
103
+ attribute: Attr,
104
+ referencedIds?: Set<string>,
105
+ ): void {
106
+ const attributeName = attribute.localName.toLowerCase();
107
+ const value = attribute.value.trim();
108
+ if (attributeName === "href" || attributeName === "src") {
109
+ if (!value.startsWith("#")) {
110
+ throw new ToolcraftArtifactExportError({
111
+ code: "svg-content-invalid",
112
+ message: `SVG export cannot contain external ${attribute.name} references.`,
113
+ });
114
+ }
115
+ const referencedId = value.slice(1).trim();
116
+ if (!referencedId) {
117
+ throw new ToolcraftArtifactExportError({
118
+ code: "svg-content-invalid",
119
+ message: `SVG export ${attribute.name} references must name a local element.`,
120
+ });
121
+ }
122
+ referencedIds?.add(referencedId);
123
+ }
124
+
125
+ const urlPattern = /url\(\s*(['"]?)(.*?)\1\s*\)/giu;
126
+ for (const match of value.matchAll(urlPattern)) {
127
+ const reference = match[2]?.trim() ?? "";
128
+ if (!reference.startsWith("#")) {
129
+ throw new ToolcraftArtifactExportError({
130
+ code: "svg-content-invalid",
131
+ message: `SVG export cannot contain external url() references in ${attribute.name}.`,
132
+ });
133
+ }
134
+ const referencedId = reference.slice(1).trim();
135
+ if (!referencedId) {
136
+ throw new ToolcraftArtifactExportError({
137
+ code: "svg-content-invalid",
138
+ message: `SVG export url() in ${attribute.name} must name a local element.`,
139
+ });
140
+ }
141
+ referencedIds?.add(referencedId);
142
+ }
143
+ }
144
+
145
+ function validateProductContainer(container: Element): number {
146
+ if (
147
+ container.namespaceURI !== TOOLCRAFT_SVG_NAMESPACE ||
148
+ container.localName !== "g" ||
149
+ container.getAttribute(TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE) !== "true"
150
+ ) {
151
+ throw new ToolcraftArtifactExportError({
152
+ code: "svg-content-invalid",
153
+ message: "SVG product content must use the runtime-owned SVG group.",
154
+ });
155
+ }
156
+
157
+ let vectorElementCount = 0;
158
+ const definedIds = new Set<string>();
159
+ const referencedIds = new Set<string>();
160
+ const elements = [container, ...container.querySelectorAll("*")];
161
+ for (const element of elements) {
162
+ for (const node of element.childNodes) {
163
+ if (node.nodeType !== Node.ELEMENT_NODE && node.nodeType !== Node.TEXT_NODE) {
164
+ throw new ToolcraftArtifactExportError({
165
+ code: "svg-content-invalid",
166
+ message: "SVG export content may contain only elements and text nodes.",
167
+ });
168
+ }
169
+ }
170
+ if (element.namespaceURI !== TOOLCRAFT_SVG_NAMESPACE) {
171
+ throw new ToolcraftArtifactExportError({
172
+ code: "svg-content-invalid",
173
+ message: "SVG export content must use the SVG namespace.",
174
+ });
175
+ }
176
+
177
+ const elementName = element.localName.toLowerCase();
178
+ if (
179
+ (element !== container &&
180
+ element.hasAttribute(TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE)) ||
181
+ element.hasAttribute(TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE)
182
+ ) {
183
+ throw new ToolcraftArtifactExportError({
184
+ code: "svg-content-invalid",
185
+ message: "SVG product content cannot use runtime-owned marker attributes.",
186
+ });
187
+ }
188
+ if (forbiddenElementNames.has(elementName)) {
189
+ throw new ToolcraftArtifactExportError({
190
+ code: "svg-content-invalid",
191
+ message: `SVG export cannot contain <${element.localName}> content.`,
192
+ });
193
+ }
194
+ if (
195
+ vectorPrimitiveNames.has(elementName) &&
196
+ !hasNonRenderingAncestor(element, container)
197
+ ) {
198
+ vectorElementCount += 1;
199
+ }
200
+
201
+ for (const attribute of element.attributes) {
202
+ if (attribute.localName.toLowerCase() === "id") {
203
+ const id = attribute.value.trim();
204
+ if (!id || definedIds.has(id)) {
205
+ throw new ToolcraftArtifactExportError({
206
+ code: "svg-content-invalid",
207
+ message: "SVG export element ids must be non-empty and unique.",
208
+ });
209
+ }
210
+ definedIds.add(id);
211
+ }
212
+ if (attribute.localName.toLowerCase().startsWith("on")) {
213
+ throw new ToolcraftArtifactExportError({
214
+ code: "svg-content-invalid",
215
+ message: `SVG export cannot contain event attribute ${attribute.name}.`,
216
+ });
217
+ }
218
+ validateUrlReferences(attribute, referencedIds);
219
+ }
220
+ }
221
+
222
+ for (const referencedId of referencedIds) {
223
+ if (!definedIds.has(referencedId)) {
224
+ throw new ToolcraftArtifactExportError({
225
+ code: "svg-content-invalid",
226
+ message: `SVG export local reference #${referencedId} has no matching element.`,
227
+ });
228
+ }
229
+ }
230
+
231
+ if (vectorElementCount === 0) {
232
+ throw new ToolcraftArtifactExportError({
233
+ code: "svg-content-empty",
234
+ message: "SVG export must contain at least one visible vector primitive.",
235
+ });
236
+ }
237
+ return vectorElementCount;
238
+ }
239
+
240
+ function createBackground(
241
+ svgDocument: XMLDocument,
242
+ frame: ToolcraftExportFrame,
243
+ color: string,
244
+ ): SVGRectElement {
245
+ if (!color.trim()) {
246
+ throw new ToolcraftArtifactExportError({
247
+ code: "svg-content-invalid",
248
+ message: "SVG export background color must not be blank.",
249
+ });
250
+ }
251
+ const background = svgDocument.createElementNS(
252
+ TOOLCRAFT_SVG_NAMESPACE,
253
+ "rect",
254
+ );
255
+ background.setAttribute(TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE, "true");
256
+ background.setAttribute("fill", color);
257
+ background.setAttribute("x", String(frame.x));
258
+ background.setAttribute("y", String(frame.y));
259
+ background.setAttribute("width", String(frame.width));
260
+ background.setAttribute("height", String(frame.height));
261
+ const fill = background.getAttributeNode("fill");
262
+ if (fill) validateUrlReferences(fill);
263
+ return background;
264
+ }
265
+
266
+ function requireStrictSvgSource(
267
+ source: string,
268
+ frame: ToolcraftExportFrame,
269
+ backgroundColor: string | null,
270
+ expectedVectorElementCount: number,
271
+ ): void {
272
+ const parsed = new DOMParser().parseFromString(source, "image/svg+xml");
273
+ if (parsed.getElementsByTagName("parsererror").length > 0) {
274
+ throw new ToolcraftArtifactExportError({
275
+ code: "svg-serialization-failed",
276
+ message: "Serialized SVG export is not valid XML.",
277
+ });
278
+ }
279
+ const root = parsed.documentElement;
280
+ if (
281
+ root.localName !== "svg" ||
282
+ root.namespaceURI !== TOOLCRAFT_SVG_NAMESPACE ||
283
+ root.getAttribute("width") !== String(frame.width) ||
284
+ root.getAttribute("height") !== String(frame.height) ||
285
+ root.getAttribute("viewBox") !==
286
+ `${frame.x} ${frame.y} ${frame.width} ${frame.height}`
287
+ ) {
288
+ throw new ToolcraftArtifactExportError({
289
+ code: "svg-serialization-failed",
290
+ message: "Serialized SVG export lost its runtime-owned frame metadata.",
291
+ });
292
+ }
293
+
294
+ const productContainers = root.querySelectorAll(
295
+ `[${TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE}]`,
296
+ );
297
+ const backgrounds = root.querySelectorAll(
298
+ `[${TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE}]`,
299
+ );
300
+ const productContainer = productContainers[0];
301
+ const expectedChildCount = backgroundColor === null ? 1 : 2;
302
+ if (
303
+ productContainers.length !== 1 ||
304
+ !productContainer ||
305
+ productContainer.parentElement !== root ||
306
+ root.children.length !== expectedChildCount ||
307
+ root.children[expectedChildCount - 1] !== productContainer ||
308
+ validateProductContainer(productContainer) !== expectedVectorElementCount
309
+ ) {
310
+ throw new ToolcraftArtifactExportError({
311
+ code: "svg-serialization-failed",
312
+ message: "Serialized SVG export lost its runtime-owned product structure.",
313
+ });
314
+ }
315
+
316
+ if (backgroundColor === null) {
317
+ if (backgrounds.length > 0) {
318
+ throw new ToolcraftArtifactExportError({
319
+ code: "svg-serialization-failed",
320
+ message: "Serialized SVG export gained an unexpected background.",
321
+ });
322
+ }
323
+ return;
324
+ }
325
+
326
+ const background = backgrounds[0];
327
+ if (
328
+ backgrounds.length !== 1 ||
329
+ !background ||
330
+ background.localName !== "rect" ||
331
+ background.parentElement !== root ||
332
+ root.children[0] !== background ||
333
+ background.getAttribute("fill") !== backgroundColor ||
334
+ background.getAttribute("x") !== String(frame.x) ||
335
+ background.getAttribute("y") !== String(frame.y) ||
336
+ background.getAttribute("width") !== String(frame.width) ||
337
+ background.getAttribute("height") !== String(frame.height)
338
+ ) {
339
+ throw new ToolcraftArtifactExportError({
340
+ code: "svg-serialization-failed",
341
+ message: "Serialized SVG export lost its runtime-owned background.",
342
+ });
343
+ }
344
+ }
345
+
346
+ export function serializeToolcraftSvgDocument({
347
+ backgroundColor,
348
+ container,
349
+ document: svgDocument,
350
+ frame,
351
+ }: Readonly<{
352
+ backgroundColor: string | null;
353
+ container: SVGGElement;
354
+ document: XMLDocument;
355
+ frame: ToolcraftExportFrame;
356
+ }>): ToolcraftSerializedSvgDocument {
357
+ try {
358
+ const vectorElementCount = validateProductContainer(container);
359
+ const root = svgDocument.querySelector("svg");
360
+ if (!root) {
361
+ throw new ToolcraftArtifactExportError({
362
+ code: "svg-document-invalid",
363
+ message: "Runtime SVG document is missing its root.",
364
+ });
365
+ }
366
+ if (root.childNodes.length > 0) {
367
+ throw new ToolcraftArtifactExportError({
368
+ code: "svg-document-invalid",
369
+ message: "Runtime SVG document must be assembled exactly once.",
370
+ });
371
+ }
372
+
373
+ const productContent = svgDocument.importNode(container, true);
374
+ const nodes: Node[] =
375
+ backgroundColor === null
376
+ ? [productContent]
377
+ : [createBackground(svgDocument, frame, backgroundColor), productContent];
378
+ root.append(...nodes);
379
+
380
+ const source = `<?xml version="1.0" encoding="UTF-8"?>\n${new XMLSerializer().serializeToString(svgDocument)}`;
381
+ requireStrictSvgSource(
382
+ source,
383
+ frame,
384
+ backgroundColor,
385
+ vectorElementCount,
386
+ );
387
+ return Object.freeze({ source, vectorElementCount });
388
+ } catch (error) {
389
+ if (error instanceof ToolcraftArtifactExportError) {
390
+ throw error;
391
+ }
392
+ throw new ToolcraftArtifactExportError(
393
+ {
394
+ code: "svg-serialization-failed",
395
+ message: "Toolcraft could not serialize the SVG export.",
396
+ },
397
+ { cause: error },
398
+ );
399
+ }
400
+ }
@@ -0,0 +1,47 @@
1
+ export const TOOLCRAFT_SVG_NAMESPACE = "http://www.w3.org/2000/svg" as const;
2
+ export const TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE =
3
+ "data-toolcraft-background" as const;
4
+ export const TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE =
5
+ "data-toolcraft-product-scene" as const;
6
+
7
+ export const TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS = Object.freeze([
8
+ "animate",
9
+ "animatecolor",
10
+ "animatemotion",
11
+ "animatetransform",
12
+ "audio",
13
+ "canvas",
14
+ "discard",
15
+ "embed",
16
+ "feimage",
17
+ "foreignobject",
18
+ "handler",
19
+ "iframe",
20
+ "image",
21
+ "object",
22
+ "script",
23
+ "set",
24
+ "style",
25
+ "video",
26
+ ] as const);
27
+
28
+ export const TOOLCRAFT_SVG_VECTOR_PRIMITIVES = Object.freeze([
29
+ "circle",
30
+ "ellipse",
31
+ "line",
32
+ "path",
33
+ "polygon",
34
+ "polyline",
35
+ "rect",
36
+ "text",
37
+ "use",
38
+ ] as const);
39
+
40
+ export const TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS = Object.freeze([
41
+ "clippath",
42
+ "defs",
43
+ "marker",
44
+ "mask",
45
+ "pattern",
46
+ "symbol",
47
+ ] as const);
@@ -13,6 +13,9 @@ export type {
13
13
  } from "./react/model-rendering/model-render-binding";
14
14
  export * from "./schema/define-toolcraft";
15
15
  export { TOOLCRAFT_CANVAS_RENDER_SCALE } from "./schema/canvas-render-scale";
16
+ export * from "./schema/collection-item-controls";
17
+ export * from "./schema/control-applicability";
18
+ export * from "./schema/artifact-export-actions";
16
19
  export * from "./schema/keyframe-capability";
17
20
  export * from "./schema/runtime-targets";
18
21
  export * from "./schema/types";
@@ -1,5 +1,4 @@
1
1
  import type {
2
- ResolvedToolcraftModelFileDropSchema,
3
2
  ToolcraftModelFormat,
4
3
  ToolcraftModelFileDropSchema,
5
4
  ToolcraftModelImportLimits,
@@ -143,9 +142,21 @@ function normalizeTopologyProfile(
143
142
  return normalizedProfile;
144
143
  }
145
144
 
146
- export function normalizeToolcraftModelFileDrop(
147
- control: ToolcraftModelFileDropSchema,
148
- ): ResolvedToolcraftModelFileDropSchema {
145
+ type NormalizedToolcraftModelFileDropSchema<
146
+ TControl extends ToolcraftModelFileDropSchema,
147
+ > = Omit<
148
+ TControl,
149
+ "modelFormats" | "modelLimits" | "multiple" | "topologyProfile"
150
+ > & {
151
+ modelFormats: readonly ToolcraftModelFormat[];
152
+ modelLimits: ToolcraftModelImportLimits;
153
+ multiple: false;
154
+ topologyProfile: ToolcraftModelTopologyProfile;
155
+ };
156
+
157
+ export function normalizeToolcraftModelFileDrop<
158
+ TControl extends ToolcraftModelFileDropSchema,
159
+ >(control: TControl): NormalizedToolcraftModelFileDropSchema<TControl> {
149
160
  const multiple: unknown = control.multiple;
150
161
 
151
162
  if (multiple !== undefined && multiple !== false) {
@@ -9,6 +9,7 @@ import * as ToolcraftReact from "../index";
9
9
  import {
10
10
  isToolcraftLayerVisibleInTree,
11
11
  useToolcraftMediaPresentationUrls,
12
+ useToolcraftProductSceneFrame,
12
13
  } from "../index";
13
14
  import { CanvasShell } from "../canvas/canvas-shell";
14
15
  import { ControlsPanel } from "../controls-panel/controls-panel";
@@ -39,6 +40,14 @@ describe("Toolcraft template runtime public API", () => {
39
40
  expect(ToolcraftRuntime).not.toHaveProperty(
40
41
  "toolcraftControlsResetHistorySource",
41
42
  );
43
+ expect(ToolcraftRuntime.TOOLCRAFT_SVG_NAMESPACE).toBe(
44
+ "http://www.w3.org/2000/svg",
45
+ );
46
+ expect(ToolcraftRuntime).not.toHaveProperty("exportToolcraftSvgArtifact");
47
+ expect(ToolcraftRuntime).not.toHaveProperty("createToolcraftSvgDocument");
48
+ expect(ToolcraftRuntime).not.toHaveProperty(
49
+ "serializeToolcraftSvgDocument",
50
+ );
42
51
  expect(ToolcraftReact.useToolcraftDispatch).toBe(useToolcraftDispatch);
43
52
  expect(ToolcraftReact.useToolcraftSelector).toBe(useToolcraftSelector);
44
53
  expect(ToolcraftReact.useToolcraftPipeline).toBe(useToolcraftPipeline);
@@ -53,6 +62,10 @@ describe("Toolcraft template runtime public API", () => {
53
62
  isToolcraftLayerVisibleInTree,
54
63
  );
55
64
  expect(isToolcraftLayerVisibleInTree).toEqual(expect.any(Function));
65
+ expect(ToolcraftReact.useToolcraftProductSceneFrame).toBe(
66
+ useToolcraftProductSceneFrame,
67
+ );
68
+ expect(useToolcraftProductSceneFrame).toEqual(expect.any(Function));
56
69
  expect(ToolcraftReact).not.toHaveProperty("ToolcraftStoreContext");
57
70
  expect(ToolcraftReact).not.toHaveProperty("useToolcraftStore");
58
71
  });
@@ -71,12 +84,14 @@ describe("Toolcraft template runtime public API", () => {
71
84
  | "canvasContent"
72
85
  | "controlRenderers"
73
86
  | "exportRenderer"
87
+ | "infiniteCanvasContent"
74
88
  | "modelPresentation"
75
89
  | "onPanelAction"
76
90
  | "renderDefaultCanvasMedia"
77
91
  | "rendererPipelineRegistration"
78
92
  | "sceneBoundsProvider"
79
93
  | "schema"
94
+ | "svgExportRenderer"
80
95
  >();
81
96
  expectTypeOf<
82
97
  keyof React.ComponentProps<typeof ToolcraftApp>
@@ -85,6 +100,7 @@ describe("Toolcraft template runtime public API", () => {
85
100
  | "className"
86
101
  | "controlRenderers"
87
102
  | "exportRenderer"
103
+ | "infiniteCanvasContent"
88
104
  | "modelPresentation"
89
105
  | "onPanelAction"
90
106
  | "renderDefaultCanvasMedia"
@@ -92,6 +108,7 @@ describe("Toolcraft template runtime public API", () => {
92
108
  | "sceneBoundsProvider"
93
109
  | "schema"
94
110
  | "style"
111
+ | "svgExportRenderer"
95
112
  >();
96
113
  expectTypeOf<
97
114
  keyof React.ComponentProps<typeof ToolcraftRoot>
@@ -153,7 +170,9 @@ describe("Toolcraft template runtime public API", () => {
153
170
  it("keeps shell and panel host props separate", () => {
154
171
  expectTypeOf<
155
172
  keyof React.ComponentProps<typeof CanvasShell>
156
- >().toEqualTypeOf<"children" | "renderDefaultMedia">();
173
+ >().toEqualTypeOf<
174
+ "children" | "infiniteCanvasContent" | "renderDefaultMedia"
175
+ >();
157
176
  expectTypeOf<React.ComponentProps<typeof PanelHost>>().toHaveProperty(
158
177
  "panelType",
159
178
  );
@@ -211,6 +230,7 @@ describe("Toolcraft template runtime public API", () => {
211
230
  };
212
231
  const canvasWithSlotProps: React.ComponentProps<typeof CanvasShell> = {
213
232
  children: <div />,
233
+ infiniteCanvasContent: <div />,
214
234
  renderDefaultMedia: false,
215
235
  };
216
236
  // @ts-expect-error Canvas upload belongs to schema.canvas.upload.
@@ -18,6 +18,12 @@ function createSettingsSchema() {
18
18
  sections: [
19
19
  {
20
20
  controls: {
21
+ fill: {
22
+ defaultValue: "#112233",
23
+ label: "Fill",
24
+ target: "appearance.fill",
25
+ type: "color",
26
+ },
21
27
  prompt: {
22
28
  defaultValue: "Initial prompt",
23
29
  label: "Prompt",
@@ -250,4 +256,19 @@ describe("settings transfer", () => {
250
256
 
251
257
  expect(state.values["style.opacity"]).toBe(75);
252
258
  });
259
+
260
+ it("canonicalizes legacy Color payloads during settings import", () => {
261
+ const schema = createSettingsSchema();
262
+ const initialState = createToolcraftState(schema);
263
+ const payload = {
264
+ ...createToolcraftSettingsPayload(initialState),
265
+ values: { "appearance.fill": { hex: "#abc" } },
266
+ };
267
+
268
+ const state = reduceWithCommands(initialState, (dispatch) => {
269
+ applyToolcraftSettingsPayload({ dispatch, state: initialState }, payload);
270
+ });
271
+
272
+ expect(state.values["appearance.fill"]).toBe("#AABBCC");
273
+ });
253
274
  });
@@ -10,6 +10,35 @@ afterEach(() => {
10
10
  });
11
11
 
12
12
  describe("ToolcraftApp scene export boundary", () => {
13
+ it("applies composition scene bounds to the live infinite product surface", () => {
14
+ const schema = defineToolcraft({
15
+ canvas: {
16
+ enabled: true,
17
+ size: { height: 180, unit: "px", width: 320 },
18
+ sizing: { defaultMode: "infinite", mode: "editable-output" },
19
+ },
20
+ panels: {},
21
+ persistence: { storage: "none" },
22
+ });
23
+ const { container } = render(
24
+ <ToolcraftApp
25
+ canvasContent={<div data-testid="product-scene" />}
26
+ sceneBoundsProvider={() => [
27
+ { height: 240, width: 400, x: -200, y: -120 },
28
+ ]}
29
+ schema={schema}
30
+ />,
31
+ );
32
+ const productScene = container.querySelector<HTMLElement>(
33
+ "[data-toolcraft-product-scene]",
34
+ );
35
+
36
+ expect(productScene?.style.height).toBe("240px");
37
+ expect(productScene?.style.left).toBe("-200px");
38
+ expect(productScene?.style.top).toBe("-120px");
39
+ expect(productScene?.style.width).toBe("400px");
40
+ });
41
+
13
42
  it("fails before mount when a typed product export has no shared renderer", () => {
14
43
  const schema = defineToolcraft({
15
44
  canvas: {
@@ -48,6 +77,51 @@ describe("ToolcraftApp scene export boundary", () => {
48
77
  schema={schema}
49
78
  />,
50
79
  ),
51
- ).toThrow("Product-owned export actions require exportRenderer");
80
+ ).toThrow("Product-owned image/video export actions require exportRenderer");
81
+ });
82
+
83
+ it("requires typed SVG actions and SVG renderers to correspond", () => {
84
+ const schema = defineToolcraft({
85
+ canvas: { enabled: true },
86
+ panels: {
87
+ controls: {
88
+ sections: [
89
+ {
90
+ controls: {
91
+ footer: {
92
+ actions: [
93
+ {
94
+ label: "Export SVG",
95
+ role: "export-svg",
96
+ value: "export.svg",
97
+ },
98
+ ],
99
+ target: "actions.output",
100
+ type: "panelActions",
101
+ },
102
+ },
103
+ },
104
+ ],
105
+ title: "Controls",
106
+ },
107
+ },
108
+ persistence: { storage: "none" },
109
+ });
110
+
111
+ expect(() => render(<ToolcraftApp schema={schema} />)).toThrow(
112
+ "A typed SVG export action requires svgExportRenderer",
113
+ );
114
+ expect(() =>
115
+ render(
116
+ <ToolcraftApp
117
+ schema={defineToolcraft({
118
+ canvas: { enabled: true },
119
+ panels: {},
120
+ persistence: { storage: "none" },
121
+ })}
122
+ svgExportRenderer={{ baseFileName: "vector", renderFrame: () => {} }}
123
+ />,
124
+ ),
125
+ ).toThrow("svgExportRenderer requires a typed SVG export action");
52
126
  });
53
127
  });