@pixel-point/toolcraft 0.0.18 → 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 (384) 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 +55 -53
  8. package/src/generate-test-doc-assertions.test.mjs +1 -1
  9. package/src/generate-test-doc-policy-assertions.mjs +1 -1
  10. package/src/generate-test-export-doc-assertions.mjs +53 -0
  11. package/src/generate-test-file-assertions.mjs +51 -8
  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 +0 -1
  20. package/src/generate-test-runtime-boundary-assertions.mjs +20 -0
  21. package/src/generate-test-standalone-assertions.mjs +0 -16
  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 +18 -3
  34. package/templates/runtime/contracts/component-contracts.choices.ts +8 -3
  35. package/templates/runtime/contracts/component-contracts.inputs.ts +2 -1
  36. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +18 -4
  37. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
  38. package/templates/runtime/contracts/component-contracts.runtime.ts +7 -4
  39. package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
  40. package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
  41. package/templates/runtime/contracts/decision-contracts.test.ts +18 -12
  42. package/templates/runtime/contracts/decision-contracts.ts +4 -4
  43. package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
  44. package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
  45. package/templates/runtime/export/artifact-download.ts +1 -0
  46. package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
  47. package/templates/runtime/export/artifact-frame-state.ts +16 -0
  48. package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
  49. package/templates/runtime/export/artifact-scene-frame.ts +3 -3
  50. package/templates/runtime/export/export-error.ts +5 -0
  51. package/templates/runtime/export/export-renderer-coverage.ts +54 -0
  52. package/templates/runtime/export/image-artifact-export.ts +2 -2
  53. package/templates/runtime/export/index.ts +13 -0
  54. package/templates/runtime/export/product-export-renderer.test.ts +38 -4
  55. package/templates/runtime/export/product-export-renderer.ts +0 -41
  56. package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
  57. package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
  58. package/templates/runtime/export/svg-artifact-export.ts +120 -0
  59. package/templates/runtime/export/svg-document.test.ts +221 -0
  60. package/templates/runtime/export/svg-document.ts +400 -0
  61. package/templates/runtime/export/svg-policy.ts +47 -0
  62. package/templates/runtime/index.ts +1 -0
  63. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +10 -0
  64. package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
  65. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +46 -1
  66. package/templates/runtime/react/app-shell/toolcraft-app.tsx +7 -2
  67. package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
  68. package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
  69. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +1 -1
  70. package/templates/runtime/react/canvas/canvas-shell.tsx +16 -5
  71. package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
  72. package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
  73. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
  74. package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
  75. package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
  76. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +39 -0
  77. package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
  78. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +1 -4
  79. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +2 -2
  80. package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
  81. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +2 -2
  82. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +40 -11
  83. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +31 -2
  84. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +4 -1
  85. package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
  86. package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
  87. package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
  88. package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
  89. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
  90. package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
  91. package/templates/runtime/schema/artifact-export-actions.ts +49 -0
  92. package/templates/runtime/schema/types.ts +1 -0
  93. package/templates/runtime/state/canvas-background-state.ts +1 -16
  94. package/templates/runtime/state/canvas-state.ts +32 -20
  95. package/templates/runtime/state/control-value-codecs.test.ts +98 -0
  96. package/templates/runtime/state/control-value-codecs.ts +700 -0
  97. package/templates/runtime/state/control-value-normalization.test.ts +1 -1
  98. package/templates/runtime/state/control-value-normalization.ts +127 -135
  99. package/templates/runtime/state/controls-reducer.ts +26 -3
  100. package/templates/runtime/state/create-template-state.test.ts +30 -0
  101. package/templates/runtime/state/create-template-state.ts +52 -31
  102. package/templates/runtime/state/orientation-pose.ts +80 -0
  103. package/templates/runtime/state/persistence-control-values.test.ts +59 -0
  104. package/templates/runtime/state/reducer-controls.test.ts +45 -0
  105. package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
  106. package/templates/runtime/state/reducer-timeline.test.ts +70 -0
  107. package/templates/runtime/state/timeline-reducer.ts +40 -2
  108. package/templates/runtime/testing/performance-schema-queries.ts +2 -2
  109. package/templates/starter/AGENTS.md +21 -22
  110. package/templates/starter/docs/toolcraft/README.md +6 -6
  111. package/templates/starter/docs/toolcraft/acceptance-testing.md +20 -20
  112. package/templates/starter/docs/toolcraft/agent-worklog.md +88 -1
  113. package/templates/starter/docs/toolcraft/assembly-workflow.md +7 -6
  114. package/templates/starter/docs/toolcraft/component-rules.md +2 -2
  115. package/templates/starter/docs/toolcraft/core/layout.md +6 -1
  116. package/templates/starter/docs/toolcraft/core/media-upload.md +1 -1
  117. package/templates/starter/docs/toolcraft/core/performance.md +8 -10
  118. package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
  119. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +2 -1
  120. package/templates/starter/docs/toolcraft/core/setup-export.md +43 -13
  121. package/templates/starter/docs/toolcraft/decision-contract.md +2 -2
  122. package/templates/starter/docs/toolcraft/performance.md +8 -10
  123. package/templates/starter/docs/toolcraft/renderer-technique.md +2 -2
  124. package/templates/starter/docs/toolcraft/schema-reference.md +8 -8
  125. package/templates/starter/docs/toolcraft/workflow.md +14 -14
  126. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +38 -0
  127. package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
  128. package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
  129. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +62 -0
  130. package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
  131. package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
  132. package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
  133. package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
  134. package/templates/starter/e2e/browser-proof-session.ts +43 -15
  135. package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
  136. package/templates/starter/e2e/browser-proof-types.ts +15 -0
  137. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +22 -6
  138. package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
  139. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +97 -0
  140. package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
  141. package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
  142. package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
  143. package/templates/starter/e2e/product-observable-helpers.ts +8 -129
  144. package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
  145. package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
  146. package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
  147. package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
  148. package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
  149. package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
  150. package/templates/starter/package.json +2 -0
  151. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  152. package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
  153. package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
  154. package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
  155. package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
  156. package/templates/starter/scripts/run-browser-performance.mjs +0 -6
  157. package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
  158. package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
  159. package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
  160. package/templates/starter/scripts/run-feature-verification.mjs +212 -0
  161. package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
  162. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
  163. package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
  164. package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
  165. package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
  166. package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
  167. package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
  168. package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
  169. package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
  170. package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
  171. package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
  172. package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
  173. package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
  174. package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
  175. package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
  176. package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
  177. package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
  178. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
  179. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
  180. package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
  181. package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
  182. package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
  183. package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
  184. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
  185. package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
  186. package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
  187. package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
  188. package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
  189. package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
  190. package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
  191. package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
  192. package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
  193. package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
  194. package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
  195. package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
  196. package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
  197. package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
  198. package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
  199. package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
  200. package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
  201. package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
  202. package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
  203. package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
  204. package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
  205. package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
  206. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
  207. package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
  208. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
  209. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
  210. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
  211. package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
  212. package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
  213. package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
  214. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
  215. package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
  216. package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
  217. package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
  218. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
  219. package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
  220. package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
  221. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
  222. package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
  223. package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
  224. package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
  225. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
  226. package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
  227. package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
  228. package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
  229. package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
  230. package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
  231. package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
  232. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
  233. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
  234. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
  235. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
  236. package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
  237. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
  238. package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
  239. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
  240. package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
  241. package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
  242. package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
  243. package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
  244. package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
  245. package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
  246. package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
  247. package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
  248. package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
  249. package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
  250. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
  251. package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
  252. package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
  253. package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
  254. package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
  255. package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
  256. package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
  257. package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
  258. package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
  259. package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
  260. package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
  261. package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
  262. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +1 -1
  263. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +10 -1
  264. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +5 -1
  265. package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
  266. package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
  267. package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
  268. package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
  269. package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
  270. package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
  271. package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
  272. package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
  273. package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
  274. package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
  275. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
  276. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
  277. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
  278. package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
  279. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
  280. package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
  281. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +51 -20
  282. package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
  283. package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
  284. package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
  285. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +0 -11
  286. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -3
  287. package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
  288. package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
  289. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +18 -0
  290. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
  291. package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
  292. package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
  293. package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
  294. package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
  295. package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
  296. package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
  297. package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
  298. package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
  299. package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
  300. package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
  301. package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
  302. package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
  303. package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
  304. package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
  305. package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
  306. package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
  307. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +5 -1
  308. package/templates/starter/src/app/acceptance/output-export-model.ts +4 -0
  309. package/templates/starter/src/app/acceptance/output-export.ts +4 -1
  310. package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
  311. package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
  312. package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
  313. package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
  314. package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
  315. package/templates/starter/src/app/acceptance/types.ts +43 -118
  316. package/templates/starter/src/app/acceptance/validate-coverage.ts +14 -3
  317. package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
  318. package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
  319. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +81 -8
  320. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +2 -0
  321. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +2 -0
  322. package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
  323. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +1 -1
  324. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +1 -0
  325. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +1 -0
  326. package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
  327. package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
  328. package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
  329. package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
  330. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
  331. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +5 -1
  332. package/templates/starter/src/app/starter-acceptance.image-export-settings.test.ts +2 -0
  333. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +19 -3
  334. package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
  335. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
  336. package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
  337. package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
  338. package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
  339. package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
  340. package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
  341. package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
  342. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +78 -4
  343. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +6 -1
  344. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +18 -1
  345. package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
  346. package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
  347. package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
  348. package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
  349. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +2 -0
  350. package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
  351. package/templates/starter/src/app/starter-acceptance.ts +34 -8
  352. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +2 -0
  353. package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
  354. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +4 -0
  355. package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
  356. package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
  357. package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
  358. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
  359. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +3 -0
  360. package/templates/starter/tsconfig.json +1 -0
  361. package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
  362. package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
  363. package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
  364. package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
  365. package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
  366. package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
  367. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
  368. package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
  369. package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
  370. package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
  371. package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
  372. package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
  373. package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
  374. package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
  375. package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
  376. package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
  377. package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
  378. package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
  379. package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
  380. package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
  381. package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
  382. package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
  383. package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
  384. package/templates/starter/src/app/starter-verification-impact.json +0 -15
@@ -60,7 +60,7 @@ describe("ControlsPanel vector pad interactions", () => {
60
60
  });
61
61
 
62
62
  const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
63
- expect(values["geometry.position"]).toEqual({ x: "-1.00", y: "-1.00" });
63
+ expect(values["geometry.position"]).toEqual({ x: -1, y: -1 });
64
64
  });
65
65
 
66
66
  it("resets a vector pad to its default value on double click", () => {
@@ -115,12 +115,12 @@ describe("ControlsPanel vector pad interactions", () => {
115
115
  JSON.parse(screen.getByTestId("values-json").textContent ?? "{}")[
116
116
  "geometry.position"
117
117
  ],
118
- ).toEqual({ x: "-1.00", y: "-1.00" });
118
+ ).toEqual({ x: -1, y: -1 });
119
119
 
120
120
  fireEvent.doubleClick(pad);
121
121
 
122
122
  const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
123
- expect(values["geometry.position"]).toEqual({ x: "0.48", y: "-0.34" });
123
+ expect(values["geometry.position"]).toEqual({ x: 0.48, y: -0.34 });
124
124
  expect(screen.getByText("0.48, -0.34")).toBeTruthy();
125
125
  });
126
126
 
@@ -181,7 +181,7 @@ describe("ControlsPanel vector pad interactions", () => {
181
181
  });
182
182
 
183
183
  const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
184
- expect(values["geometry.position"]).toEqual({ x: "0.80", y: "0.00" });
184
+ expect(values["geometry.position"]).toEqual({ x: 0.8, y: 0 });
185
185
  });
186
186
 
187
187
  it("locks vector pad movement vertically when shift drag is y-dominant", () => {
@@ -241,7 +241,7 @@ describe("ControlsPanel vector pad interactions", () => {
241
241
  });
242
242
 
243
243
  const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
244
- expect(values["geometry.position"]).toEqual({ x: "0.00", y: "0.80" });
244
+ expect(values["geometry.position"]).toEqual({ x: 0, y: 0.8 });
245
245
  });
246
246
 
247
247
  it("renders vector pad values as compact rounded coordinates", () => {
@@ -383,6 +383,6 @@ describe("ControlsPanel vector pad interactions", () => {
383
383
  });
384
384
 
385
385
  const values = JSON.parse(screen.getByTestId("values-json").textContent ?? "{}");
386
- expect(values["math.vector"]).toEqual({ x: "-1.00", y: "1.00" });
386
+ expect(values["math.vector"]).toEqual({ x: -1, y: 1 });
387
387
  });
388
388
  });
@@ -10,6 +10,7 @@ import type {
10
10
  ToolcraftActionCommand,
11
11
  ToolcraftActionSchema,
12
12
  } from "../../../schema/types";
13
+ import { isToolcraftArtifactExportAction } from "../../../schema/artifact-export-actions";
13
14
  import type {
14
15
  ToolcraftCommand,
15
16
  ToolcraftState,
@@ -204,8 +205,7 @@ export function useControlsPanelActions({
204
205
  setPanelActionFeedback(feedback);
205
206
  }
206
207
  };
207
- const runtimeOwnsExport =
208
- action.role === "export-image" || action.role === "export-video";
208
+ const runtimeOwnsExport = isToolcraftArtifactExportAction(action);
209
209
  const command = runtimeOwnsExport
210
210
  ? null
211
211
  : action.command ?? (onPanelAction ? null : getActionCommand(action));
@@ -1,16 +1,14 @@
1
- import type {
2
- ToolcraftArtifactExportRequest,
3
- } from "../../../export/artifact-export-request";
1
+ import type { ToolcraftArtifactExportRequest } from "../../../export/artifact-export-request";
2
+ import { ToolcraftArtifactExportError } from "../../../export/export-error";
4
3
  import type { ToolcraftExportFrame } from "../../../export/export-frame";
4
+ import { exportToolcraftImageArtifact } from "../../../export/image-artifact-export";
5
+ import type { ToolcraftProductExportRenderer } from "../../../export/product-export-renderer";
6
+ import type { ToolcraftProductSvgExportRenderer } from "../../../export/product-svg-export-renderer";
5
7
  import {
6
- exportToolcraftImageArtifact,
7
- } from "../../../export/image-artifact-export";
8
- import type {
9
- ToolcraftProductExportRenderer,
10
- } from "../../../export/product-export-renderer";
11
- import {
12
- exportToolcraftVideoArtifact,
13
- } from "../../../export/video-artifact-export";
8
+ exportToolcraftSvgArtifact,
9
+ type ToolcraftSvgArtifactExportRequest,
10
+ } from "../../../export/svg-artifact-export";
11
+ import { exportToolcraftVideoArtifact } from "../../../export/video-artifact-export";
14
12
  import type { ToolcraftRendererPipelineClient } from "../../../rendering";
15
13
  import type {
16
14
  ToolcraftProductSceneBoundsProvider,
@@ -23,6 +21,7 @@ export type ToolcraftControlsSceneExport = Readonly<{
23
21
  boundsProvider?: ToolcraftProductSceneBoundsProvider;
24
22
  exportRenderer?: ToolcraftProductExportRenderer;
25
23
  productSceneRequired: boolean;
24
+ svgExportRenderer?: ToolcraftProductSvgExportRenderer;
26
25
  visibility: ToolcraftRuntimeSceneVisibility;
27
26
  }>;
28
27
 
@@ -54,12 +53,42 @@ function createSharedArtifactRequest(
54
53
  };
55
54
  }
56
55
 
56
+ function requireSvgExportRenderer(
57
+ renderer: ToolcraftProductSvgExportRenderer | undefined,
58
+ ): ToolcraftProductSvgExportRenderer {
59
+ if (!renderer) {
60
+ throw new ToolcraftArtifactExportError({
61
+ code: "svg-render-failed",
62
+ message: "SVG export requires svgExportRenderer.",
63
+ });
64
+ }
65
+ return renderer;
66
+ }
67
+
68
+ function createSvgArtifactRequest(
69
+ request: ToolcraftExportActionRequest,
70
+ ): ToolcraftSvgArtifactExportRequest {
71
+ return {
72
+ boundsProvider: request.sceneExport.boundsProvider,
73
+ productSceneRequired: request.sceneExport.productSceneRequired,
74
+ rendererPipeline: request.rendererPipeline,
75
+ reportProgress: request.reportProgress,
76
+ state: request.state,
77
+ svgExportRenderer: requireSvgExportRenderer(
78
+ request.sceneExport.svgExportRenderer,
79
+ ),
80
+ visibility: request.sceneExport.visibility,
81
+ };
82
+ }
83
+
57
84
  export function runToolcraftExportAction(
58
85
  request: ToolcraftExportActionRequest,
59
86
  ): PromiseLike<unknown> | null {
60
87
  switch (request.action.role) {
61
88
  case "export-image":
62
89
  return exportToolcraftImageArtifact(createSharedArtifactRequest(request));
90
+ case "export-svg":
91
+ return exportToolcraftSvgArtifact(createSvgArtifactRequest(request));
63
92
  case "export-video":
64
93
  return exportToolcraftVideoArtifact(createSharedArtifactRequest(request));
65
94
  default:
@@ -95,6 +95,7 @@ export function getControlsRecord(
95
95
 
96
96
  export function getControlRenderGroups(
97
97
  entries: readonly ControlEntry[],
98
+ sectionHasOnlyColorFields: boolean,
98
99
  ): ControlRenderGroup[] {
99
100
  const groups: ControlRenderGroup[] = [];
100
101
  let index = 0;
@@ -107,7 +108,12 @@ export function getControlRenderGroups(
107
108
  continue;
108
109
  }
109
110
 
110
- if (entry[1].type !== "color") {
111
+ const colorBankKey = getPlainColorBankKey(
112
+ entry[1],
113
+ sectionHasOnlyColorFields,
114
+ );
115
+
116
+ if (!colorBankKey) {
111
117
  groups.push({ entry, kind: "control" });
112
118
  index += 1;
113
119
  continue;
@@ -115,7 +121,13 @@ export function getControlRenderGroups(
115
121
 
116
122
  const colorEntries: ControlEntry[] = [];
117
123
 
118
- while (entries[index]?.[1].type === "color") {
124
+ while (
125
+ entries[index] &&
126
+ getPlainColorBankKey(
127
+ entries[index][1],
128
+ sectionHasOnlyColorFields,
129
+ ) === colorBankKey
130
+ ) {
119
131
  const colorEntry = entries[index];
120
132
 
121
133
  if (colorEntry) {
@@ -144,6 +156,23 @@ export function getControlRenderGroups(
144
156
  return groups;
145
157
  }
146
158
 
159
+ function getPlainColorBankKey(
160
+ control: ToolcraftControlSchema,
161
+ sectionHasOnlyColorFields: boolean,
162
+ ): string | null {
163
+ if (control.type !== "color") {
164
+ return null;
165
+ }
166
+
167
+ if (sectionHasOnlyColorFields) {
168
+ return "color-only-section";
169
+ }
170
+
171
+ const semanticGroup = control.semanticGroup?.trim();
172
+
173
+ return semanticGroup ? `semantic:${semanticGroup}` : null;
174
+ }
175
+
147
176
  export function getControlRenderGroupIds(
148
177
  group: ControlRenderGroup,
149
178
  ): readonly string[] {
@@ -353,7 +353,10 @@ export function getControlsPanelSectionGroups({
353
353
  controlsById: visibleControls,
354
354
  layoutGroups: section.layoutGroups,
355
355
  });
356
- const renderedGroups = getControlRenderGroups(renderableEntries).map(
356
+ const renderedGroups = getControlRenderGroups(
357
+ renderableEntries,
358
+ sectionHasOnlyColorFields,
359
+ ).map(
357
360
  (group) => {
358
361
  const ids = getControlRenderGroupIds(group);
359
362
  const groupEntries =
@@ -11,6 +11,7 @@ import type {
11
11
  ToolcraftActionSchema,
12
12
  ToolcraftControlSchema,
13
13
  } from "../../../schema/types";
14
+ import { isToolcraftArtifactExportAction } from "../../../schema/artifact-export-actions";
14
15
 
15
16
  export type ActionControlRunAction = (
16
17
  action: ToolcraftActionSchema,
@@ -57,7 +58,7 @@ function getActionLabel(action: ToolcraftActionSchema): string {
57
58
  }
58
59
 
59
60
  function isExportPanelAction(action: ToolcraftActionSchema): boolean {
60
- if (action.role === "export-image" || action.role === "export-video") {
61
+ if (isToolcraftArtifactExportAction(action)) {
61
62
  return true;
62
63
  }
63
64
 
@@ -40,7 +40,7 @@ const canvasAspectRatioOptions = [
40
40
  label: preset.value,
41
41
  value: preset.value,
42
42
  })),
43
- { label: "Custom...", value: "custom" },
43
+ { label: "Custom", value: "custom" },
44
44
  ] as const;
45
45
 
46
46
  export type BasicControlCommit = (
@@ -110,64 +110,14 @@ function CanvasAspectRatioControl({
110
110
  }
111
111
  }
112
112
 
113
- function updateCustomDimension(
114
- dimension: "height" | "width",
115
- nextValue: string,
116
- meta?: ControlChangeMeta,
117
- ): void {
118
- const numberValue = Number.parseFloat(nextValue);
119
-
120
- if (!Number.isFinite(numberValue) || numberValue <= 0) {
121
- return;
122
- }
123
-
124
- const width =
125
- dimension === "width" ? Math.max(1, Math.round(numberValue)) : ratio.width;
126
- const height =
127
- dimension === "height" ? Math.max(1, Math.round(numberValue)) : ratio.height;
128
-
129
- commitRatio(
130
- {
131
- height,
132
- mode: "custom",
133
- value: `${width}:${height}`,
134
- width,
135
- },
136
- meta,
137
- );
138
- }
139
-
140
113
  return (
141
- <div className="min-w-0 space-y-2" data-slot="canvas-aspect-ratio-control">
114
+ <div className="min-w-0" data-slot="canvas-aspect-ratio-control">
142
115
  <Select
143
116
  name={name}
144
117
  onValueChange={updatePreset}
145
118
  options={canvasAspectRatioOptions}
146
119
  value={selectedValue}
147
120
  />
148
- {ratio.mode === "custom" ? (
149
- <TextInput
150
- inputs={[
151
- {
152
- commitOnBlur: true,
153
- defaultValue: String(ratio.width),
154
- name: "Width",
155
- onValueChange: (nextValue, meta) =>
156
- updateCustomDimension("width", nextValue, meta),
157
- value: String(ratio.width),
158
- },
159
- {
160
- commitOnBlur: true,
161
- defaultValue: String(ratio.height),
162
- name: "Height",
163
- onValueChange: (nextValue, meta) =>
164
- updateCustomDimension("height", nextValue, meta),
165
- value: String(ratio.height),
166
- },
167
- ]}
168
- inputsPerRow={2}
169
- />
170
- ) : null}
171
121
  </div>
172
122
  );
173
123
  }
@@ -24,15 +24,7 @@ export const defaultChannelMixerValues = {
24
24
  } satisfies ChannelMixerValues;
25
25
 
26
26
  export function asColorValue(value: unknown): { hex: string } {
27
- if (typeof value === "string") {
28
- return { hex: value };
29
- }
30
-
31
- if (isRecord(value)) {
32
- return { hex: asString(value.hex, "#C1FF00") };
33
- }
34
-
35
- return { hex: "#C1FF00" };
27
+ return { hex: asString(value, "#C1FF00") };
36
28
  }
37
29
 
38
30
  export function asColorOpacityValue(value: unknown): ColorOpacityValue {
@@ -22,9 +22,14 @@ export function asRangeInputValue(value: unknown): { end: string; start: string
22
22
 
23
23
  export function asVectorValue(value: unknown): { x: string; y: string } {
24
24
  if (isRecord(value)) {
25
+ const asVectorComponent = (component: unknown): string =>
26
+ typeof component === "number" && Number.isFinite(component)
27
+ ? String(component)
28
+ : asString(component, "0.00");
29
+
25
30
  return {
26
- x: asString(value.x, "0.00"),
27
- y: asString(value.y, "0.00"),
31
+ x: asVectorComponent(value.x),
32
+ y: asVectorComponent(value.y),
28
33
  };
29
34
  }
30
35
 
@@ -10,13 +10,17 @@ import {
10
10
  scaleOrientationVector,
11
11
  type ToolcraftOrientationVector,
12
12
  } from "./orientation-quaternion";
13
+ import {
14
+ readToolcraftOrientationPose,
15
+ type ToolcraftOrientationPose,
16
+ } from "../../state/orientation-pose";
13
17
 
14
18
  export { ToolcraftOrientationQuaternion } from "./orientation-quaternion";
15
-
16
- export type ToolcraftOrientationPose = Readonly<{
17
- position: readonly [number, number, number];
18
- up: readonly [number, number, number];
19
- }>;
19
+ export {
20
+ DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
21
+ readToolcraftOrientationPose,
22
+ type ToolcraftOrientationPose,
23
+ } from "../../state/orientation-pose";
20
24
 
21
25
  export type ToolcraftOrientationAxis = "+x" | "-x" | "+y" | "-y" | "+z" | "-z";
22
26
 
@@ -28,11 +32,6 @@ export type ToolcraftOrientationAxisProjection = {
28
32
  y: number;
29
33
  };
30
34
 
31
- export const DEFAULT_TOOLCRAFT_ORIENTATION_POSE: ToolcraftOrientationPose = {
32
- position: [0, 0, 5],
33
- up: [0, 1, 0],
34
- };
35
-
36
35
  export const TOOLCRAFT_ORIENTATION_AXES: readonly ToolcraftOrientationAxis[] = [
37
36
  "+x",
38
37
  "-x",
@@ -46,7 +45,6 @@ export const TOOLCRAFT_TURNTABLE_RADIANS_PER_PIXEL = Math.PI / 450;
46
45
  export const TOOLCRAFT_ORIENTATION_SMOOTH_VIEW_MS = 200;
47
46
 
48
47
  const worldUp: ToolcraftOrientationVector = [0, 1, 0];
49
- const minimumLengthSquared = 1e-12;
50
48
 
51
49
  const axisVectors: Record<
52
50
  ToolcraftOrientationAxis,
@@ -60,64 +58,6 @@ const axisVectors: Record<
60
58
  "-z": [0, 0, -1],
61
59
  };
62
60
 
63
- function clonePose(pose: ToolcraftOrientationPose): ToolcraftOrientationPose {
64
- return {
65
- position: [...pose.position],
66
- up: [...pose.up],
67
- };
68
- }
69
-
70
- function readFiniteTuple(value: unknown): [number, number, number] | null {
71
- if (
72
- !Array.isArray(value) ||
73
- value.length !== 3 ||
74
- !value.every((entry) => typeof entry === "number" && Number.isFinite(entry))
75
- ) {
76
- return null;
77
- }
78
-
79
- return [value[0], value[1], value[2]];
80
- }
81
-
82
- function isUsablePose(pose: ToolcraftOrientationPose): boolean {
83
- const positionLength = getOrientationVectorLength(pose.position);
84
- const upLength = getOrientationVectorLength(pose.up);
85
- const crossLength = getOrientationVectorLength(
86
- crossOrientationVectors(pose.up, pose.position),
87
- );
88
-
89
- return (
90
- positionLength * positionLength > minimumLengthSquared &&
91
- upLength * upLength > minimumLengthSquared &&
92
- crossLength * crossLength > minimumLengthSquared
93
- );
94
- }
95
-
96
- export function readToolcraftOrientationPose(
97
- value: unknown,
98
- fallback: ToolcraftOrientationPose = DEFAULT_TOOLCRAFT_ORIENTATION_POSE,
99
- ): ToolcraftOrientationPose {
100
- const safeFallback = isUsablePose(fallback)
101
- ? fallback
102
- : DEFAULT_TOOLCRAFT_ORIENTATION_POSE;
103
-
104
- if (!value || typeof value !== "object") {
105
- return clonePose(safeFallback);
106
- }
107
-
108
- const record = value as Record<string, unknown>;
109
- const position = readFiniteTuple(record.position);
110
- const up = readFiniteTuple(record.up);
111
-
112
- if (!position || !up) {
113
- return clonePose(safeFallback);
114
- }
115
-
116
- const pose = { position, up };
117
-
118
- return isUsablePose(pose) ? clonePose(pose) : clonePose(safeFallback);
119
- }
120
-
121
61
  export function getToolcraftOrientationRadius(
122
62
  pose: ToolcraftOrientationPose,
123
63
  ): number {
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { defineToolcraft } from "./define-toolcraft";
4
+ import {
5
+ getToolcraftArtifactExportActions,
6
+ isToolcraftArtifactExportActionRole,
7
+ } from "./artifact-export-actions";
8
+
9
+ describe("artifact export actions", () => {
10
+ it("recognizes the closed runtime-owned role set", () => {
11
+ expect(isToolcraftArtifactExportActionRole("export-image")).toBe(true);
12
+ expect(isToolcraftArtifactExportActionRole("export-svg")).toBe(true);
13
+ expect(isToolcraftArtifactExportActionRole("export-video")).toBe(true);
14
+ expect(isToolcraftArtifactExportActionRole("download-output")).toBe(false);
15
+ });
16
+
17
+ it("collects typed export actions only from sticky panelActions", () => {
18
+ const schema = defineToolcraft({
19
+ canvas: { enabled: true },
20
+ panels: {
21
+ controls: {
22
+ sections: [
23
+ {
24
+ controls: {
25
+ local: {
26
+ actions: [{ role: "export-svg", value: "local.svg" }],
27
+ target: "local.actions",
28
+ type: "actions",
29
+ },
30
+ output: {
31
+ actions: [{ role: "export-svg", value: "export.svg" }],
32
+ target: "output.actions",
33
+ type: "panelActions",
34
+ },
35
+ },
36
+ id: "actions",
37
+ },
38
+ ],
39
+ title: "Controls",
40
+ },
41
+ },
42
+ });
43
+
44
+ expect(getToolcraftArtifactExportActions(schema).map(({ value }) => value))
45
+ .toEqual(["export.svg"]);
46
+ });
47
+ });
@@ -0,0 +1,49 @@
1
+ import type {
2
+ ResolvedToolcraftAppSchema,
3
+ ToolcraftActionRole,
4
+ ToolcraftActionSchema,
5
+ } from "./types";
6
+
7
+ export const TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES = [
8
+ "export-image",
9
+ "export-svg",
10
+ "export-video",
11
+ ] as const satisfies readonly ToolcraftActionRole[];
12
+
13
+ export type ToolcraftArtifactExportActionRole =
14
+ (typeof TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES)[number];
15
+
16
+ const artifactExportActionRoleSet = new Set<ToolcraftActionRole>(
17
+ TOOLCRAFT_ARTIFACT_EXPORT_ACTION_ROLES,
18
+ );
19
+
20
+ export function isToolcraftArtifactExportActionRole(
21
+ role: ToolcraftActionRole | undefined,
22
+ ): role is ToolcraftArtifactExportActionRole {
23
+ return role !== undefined && artifactExportActionRoleSet.has(role);
24
+ }
25
+
26
+ export function isToolcraftArtifactExportAction(
27
+ action: ToolcraftActionSchema | string,
28
+ ): action is ToolcraftActionSchema & {
29
+ role: ToolcraftArtifactExportActionRole;
30
+ } {
31
+ return (
32
+ typeof action !== "string" &&
33
+ isToolcraftArtifactExportActionRole(action.role)
34
+ );
35
+ }
36
+
37
+ export function getToolcraftArtifactExportActions(
38
+ schema: ResolvedToolcraftAppSchema,
39
+ ): readonly (ToolcraftActionSchema & {
40
+ role: ToolcraftArtifactExportActionRole;
41
+ })[] {
42
+ return (schema.panels.controls?.sections ?? []).flatMap((section) =>
43
+ Object.values(section.controls).flatMap((control) =>
44
+ control.type === "panelActions"
45
+ ? (control.actions ?? []).filter(isToolcraftArtifactExportAction)
46
+ : [],
47
+ ),
48
+ );
49
+ }
@@ -277,6 +277,7 @@ export type ToolcraftActionRole =
277
277
  | "copy-output"
278
278
  | "download-output"
279
279
  | "export-image"
280
+ | "export-svg"
280
281
  | "export-video";
281
282
 
282
283
  export type ToolcraftActionSchema = {
@@ -5,21 +5,6 @@ import {
5
5
  import type { ResolvedToolcraftAppSchema } from "../schema/types";
6
6
  import type { ToolcraftState } from "./types";
7
7
 
8
- function getToolcraftColorHex(value: unknown): string | undefined {
9
- const candidate =
10
- typeof value === "string"
11
- ? value
12
- : value !== null &&
13
- typeof value === "object" &&
14
- "hex" in value &&
15
- typeof value.hex === "string"
16
- ? value.hex
17
- : undefined;
18
- const normalized = candidate?.trim();
19
-
20
- return normalized ? normalized : undefined;
21
- }
22
-
23
8
  export function hasToolcraftRuntimeSetupBackground(
24
9
  schema: ResolvedToolcraftAppSchema,
25
10
  ): boolean {
@@ -75,5 +60,5 @@ export function getToolcraftRuntimeBackgroundColor(
75
60
  ? state.values[background.color.target] ?? background.color.defaultValue
76
61
  : undefined;
77
62
 
78
- return getToolcraftColorHex(value);
63
+ return typeof value === "string" ? value : undefined;
79
64
  }
@@ -86,32 +86,44 @@ function parseCanvasAspectRatioString(
86
86
  };
87
87
  }
88
88
 
89
- export function normalizeToolcraftCanvasAspectRatioValue(
89
+ export function decodeToolcraftCanvasAspectRatioValue(
90
90
  value: unknown,
91
- fallbackSize: ToolcraftState["canvas"]["size"],
92
- ): ToolcraftCanvasAspectRatioValue {
91
+ ): ToolcraftCanvasAspectRatioValue | null {
93
92
  if (typeof value === "string") {
94
- return parseCanvasAspectRatioString(value) ?? getToolcraftCanvasAspectRatioFromSize(fallbackSize);
93
+ return parseCanvasAspectRatioString(value);
94
+ }
95
+
96
+ if (!isRecord(value)) {
97
+ return null;
95
98
  }
96
99
 
97
- if (isRecord(value)) {
98
- const width = asToolcraftCanvasSizeDimension(value.width);
99
- const height = asToolcraftCanvasSizeDimension(value.height);
100
-
101
- if (width !== null && height !== null) {
102
- const rawValue = typeof value.value === "string" ? value.value : `${width}:${height}`;
103
- const mode = value.mode === "preset" ? "preset" : "custom";
104
-
105
- return {
106
- height,
107
- mode,
108
- value: mode === "preset" ? rawValue : `${width}:${height}`,
109
- width,
110
- };
111
- }
100
+ const width = asToolcraftCanvasSizeDimension(value.width);
101
+ const height = asToolcraftCanvasSizeDimension(value.height);
102
+
103
+ if (width === null || height === null) {
104
+ return null;
112
105
  }
113
106
 
114
- return getToolcraftCanvasAspectRatioFromSize(fallbackSize);
107
+ const rawValue =
108
+ typeof value.value === "string" ? value.value : `${width}:${height}`;
109
+ const mode = value.mode === "preset" ? "preset" : "custom";
110
+
111
+ return {
112
+ height,
113
+ mode,
114
+ value: mode === "preset" ? rawValue : `${width}:${height}`,
115
+ width,
116
+ };
117
+ }
118
+
119
+ export function normalizeToolcraftCanvasAspectRatioValue(
120
+ value: unknown,
121
+ fallbackSize: ToolcraftState["canvas"]["size"],
122
+ ): ToolcraftCanvasAspectRatioValue {
123
+ return (
124
+ decodeToolcraftCanvasAspectRatioValue(value) ??
125
+ getToolcraftCanvasAspectRatioFromSize(fallbackSize)
126
+ );
115
127
  }
116
128
 
117
129
  export function toolcraftCanvasAspectRatioValuesEqual(