@pixel-point/toolcraft 0.0.16 → 0.0.18

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 (313) hide show
  1. package/package.json +1 -1
  2. package/src/generate-performance-iteration-execution.test.mjs +2 -2
  3. package/src/generate-test-demand-only-lifecycle.mjs +14 -3
  4. package/src/generate-test-dependency-sandbox.mjs +42 -5
  5. package/src/generate-test-doc-assertions.mjs +109 -69
  6. package/src/generate-test-doc-assertions.test.mjs +65 -0
  7. package/src/generate-test-doc-policy-assertions.mjs +92 -0
  8. package/src/generate-test-file-assertions.mjs +36 -118
  9. package/src/generate-test-output-assertions.mjs +95 -0
  10. package/src/generate-test-package-assertions.mjs +6 -0
  11. package/src/generate-test-performance-boundary-assertions.mjs +45 -0
  12. package/src/generate-test-product-fixture.mjs +1 -0
  13. package/src/generate-test-product-fixture.test.mjs +18 -0
  14. package/src/generate-test-product-iteration.mjs +1 -0
  15. package/src/generate-test-product-iteration.test.mjs +18 -0
  16. package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
  17. package/src/generate-test-standalone-assertions.mjs +10 -0
  18. package/src/generate-test-standalone-delivery-stages.mjs +14 -6
  19. package/src/generate.test.mjs +14 -0
  20. package/templates/runtime/contracts/component-contracts.choices.test.ts +59 -12
  21. package/templates/runtime/contracts/component-contracts.choices.ts +58 -12
  22. package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
  23. package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
  24. package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
  25. package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
  26. package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +21 -6
  27. package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
  28. package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +4 -1
  29. package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +4 -1
  30. package/templates/runtime/contracts/component-contracts.runtime.ts +15 -10
  31. package/templates/runtime/contracts/component-contracts.test.ts +2 -0
  32. package/templates/runtime/contracts/decision-contracts.test.ts +43 -4
  33. package/templates/runtime/contracts/decision-contracts.ts +10 -10
  34. package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
  35. package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
  36. package/templates/runtime/export/artifact-download.test.ts +71 -0
  37. package/templates/runtime/export/artifact-download.ts +80 -0
  38. package/templates/runtime/export/artifact-export-request.ts +23 -0
  39. package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
  40. package/templates/runtime/export/artifact-export-settings.ts +96 -0
  41. package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
  42. package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
  43. package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
  44. package/templates/runtime/export/artifact-frame-state.ts +44 -0
  45. package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
  46. package/templates/runtime/export/artifact-scene-frame.ts +118 -0
  47. package/templates/runtime/export/export-background.ts +46 -0
  48. package/templates/runtime/export/export-error.ts +43 -0
  49. package/templates/runtime/export/export.test.ts +49 -226
  50. package/templates/runtime/export/image-artifact-export.test.ts +111 -0
  51. package/templates/runtime/export/image-artifact-export.ts +145 -0
  52. package/templates/runtime/export/index.ts +44 -3
  53. package/templates/runtime/export/product-export-renderer.test.ts +77 -0
  54. package/templates/runtime/export/product-export-renderer.ts +63 -0
  55. package/templates/runtime/export/video-artifact-export.test.ts +166 -0
  56. package/templates/runtime/export/video-artifact-export.ts +164 -0
  57. package/templates/runtime/export/video-encoding-backend.ts +124 -0
  58. package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
  59. package/templates/runtime/export/video-encoding-policy.ts +86 -0
  60. package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
  61. package/templates/runtime/export/video-frame-schedule.ts +42 -0
  62. package/templates/runtime/index.ts +3 -0
  63. package/templates/runtime/model-import/model-import-limits.ts +15 -4
  64. package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
  65. package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
  66. package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +15 -304
  67. package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +41 -27
  68. package/templates/runtime/react/app-shell/toolcraft-app.tsx +39 -11
  69. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
  70. package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
  71. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
  72. package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
  73. package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
  74. package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
  75. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
  76. package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
  77. package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
  78. package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
  79. package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
  80. package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
  81. package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
  82. package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
  83. package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
  84. package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
  85. package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
  86. package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
  87. package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +18 -84
  88. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
  89. package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
  90. package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +43 -87
  91. package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +68 -0
  92. package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
  93. package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
  94. package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
  95. package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
  96. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
  97. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
  98. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
  99. package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
  100. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
  101. package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
  102. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
  103. package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
  104. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
  105. package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
  106. package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
  107. package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
  108. package/templates/runtime/react/index.ts +4 -0
  109. package/templates/runtime/react/model-rendering/model-export.ts +1 -1
  110. package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
  111. package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
  112. package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
  113. package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
  114. package/templates/runtime/scene/scene-bounds.test.ts +23 -0
  115. package/templates/runtime/scene/scene-bounds.ts +32 -19
  116. package/templates/runtime/schema/app-capabilities.test.ts +4 -0
  117. package/templates/runtime/schema/canvas-render-scale.ts +62 -0
  118. package/templates/runtime/schema/collection-item-controls.ts +29 -0
  119. package/templates/runtime/schema/control-applicability.test.ts +127 -0
  120. package/templates/runtime/schema/control-applicability.ts +433 -0
  121. package/templates/runtime/schema/control-schema-normalization.ts +177 -11
  122. package/templates/runtime/schema/controls-panel-actions.ts +2 -2
  123. package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
  124. package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
  125. package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +62 -3
  126. package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
  127. package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
  128. package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
  129. package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
  130. package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
  131. package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
  132. package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
  133. package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
  134. package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
  135. package/templates/runtime/schema/define-toolcraft.ts +1 -1
  136. package/templates/runtime/schema/runtime-setup-section.ts +24 -5
  137. package/templates/runtime/schema/schema-resolvers.ts +0 -56
  138. package/templates/runtime/schema/types.ts +72 -17
  139. package/templates/runtime/state/canvas-background-state.ts +6 -0
  140. package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
  141. package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
  142. package/templates/starter/AGENTS.md +18 -15
  143. package/templates/starter/NOTICE.md +6 -0
  144. package/templates/starter/docs/toolcraft/README.md +2 -1
  145. package/templates/starter/docs/toolcraft/acceptance-testing.md +23 -35
  146. package/templates/starter/docs/toolcraft/agent-worklog.md +18 -3
  147. package/templates/starter/docs/toolcraft/assembly-workflow.md +13 -5
  148. package/templates/starter/docs/toolcraft/component-rules.md +8 -6
  149. package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
  150. package/templates/starter/docs/toolcraft/core/layout.md +7 -7
  151. package/templates/starter/docs/toolcraft/core/media-upload.md +4 -2
  152. package/templates/starter/docs/toolcraft/core/performance.md +14 -3
  153. package/templates/starter/docs/toolcraft/core/runtime-boundary.md +16 -3
  154. package/templates/starter/docs/toolcraft/core/setup-export.md +49 -19
  155. package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
  156. package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
  157. package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
  158. package/templates/starter/docs/toolcraft/performance.md +20 -6
  159. package/templates/starter/docs/toolcraft/renderer-technique.md +5 -1
  160. package/templates/starter/docs/toolcraft/schema-reference.md +23 -25
  161. package/templates/starter/docs/toolcraft/workflow.md +7 -2
  162. package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
  163. package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
  164. package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +50 -3
  165. package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
  166. package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
  167. package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
  168. package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
  169. package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
  170. package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +5 -34
  171. package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -16
  172. package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
  173. package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
  174. package/templates/starter/e2e/app-performance.spec.ts +16 -9
  175. package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
  176. package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
  177. package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +29 -341
  178. package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
  179. package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
  180. package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
  181. package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
  182. package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
  183. package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
  184. package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
  185. package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +13 -3
  186. package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +72 -35
  187. package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
  188. package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
  189. package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
  190. package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
  191. package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
  192. package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
  193. package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
  194. package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
  195. package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
  196. package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
  197. package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
  198. package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
  199. package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
  200. package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
  201. package/templates/starter/e2e/performance-path-helpers.ts +210 -91
  202. package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
  203. package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
  204. package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
  205. package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
  206. package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
  207. package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
  208. package/templates/starter/gitignore +1 -0
  209. package/templates/starter/package.json +1 -0
  210. package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
  211. package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
  212. package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
  213. package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
  214. package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
  215. package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +95 -103
  216. package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
  217. package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
  218. package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -26
  219. package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
  220. package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
  221. package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
  222. package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
  223. package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
  224. package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +157 -0
  225. package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
  226. package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
  227. package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
  228. package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
  229. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
  230. package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +157 -206
  231. package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
  232. package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
  233. package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
  234. package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
  235. package/templates/starter/src/app/acceptance/conditions.ts +1 -1
  236. package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
  237. package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
  238. package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
  239. package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
  240. package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
  241. package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
  242. package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
  243. package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
  244. package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
  245. package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
  246. package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
  247. package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
  248. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
  249. package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
  250. package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
  251. package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
  252. package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
  253. package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
  254. package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
  255. package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
  256. package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
  257. package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
  258. package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
  259. package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
  260. package/templates/starter/src/app/acceptance/output-export.ts +35 -12
  261. package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
  262. package/templates/starter/src/app/acceptance/types.ts +30 -8
  263. package/templates/starter/src/app/acceptance/validate-coverage.ts +20 -2
  264. package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
  265. package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
  266. package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
  267. package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
  268. package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
  269. package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
  270. package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
  271. package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
  272. package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
  273. package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
  274. package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
  275. package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
  276. package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
  277. package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
  278. package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
  279. package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
  280. package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
  281. package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
  282. package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
  283. package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +46 -1
  284. package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
  285. package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
  286. package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
  287. package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
  288. package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
  289. package/templates/starter/src/app/starter-acceptance.ts +13 -2
  290. package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
  291. package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
  292. package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
  293. package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
  294. package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
  295. package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +4 -2
  296. package/templates/starter/src/routes/index.tsx +2 -0
  297. package/templates/ui/components/composites/tabs.tsx +2 -2
  298. package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
  299. package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
  300. package/templates/ui/components/controls/collection-actions/index.ts +2 -0
  301. package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
  302. package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
  303. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
  304. package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
  305. package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
  306. package/templates/ui/components/controls/file-drop/index.ts +1 -0
  307. package/templates/ui/components/controls/index.ts +3 -0
  308. package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
  309. package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
  310. package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
  311. package/templates/runtime/export/export.ts +0 -166
  312. package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
  313. package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
@@ -1,4 +1,4 @@
1
- import type { ReactElement } from "react";
1
+ import type { ReactElement, ReactNode } from "react";
2
2
 
3
3
  import type {
4
4
  ActionControlIconName,
@@ -75,7 +75,20 @@ export type FileDropPresentation<
75
75
  status?: Status;
76
76
  };
77
77
 
78
+ export type FileDropCollectionActions = {
79
+ addLabel?: string;
80
+ canAdd?: boolean;
81
+ itemLabel?: string;
82
+ name: string;
83
+ removeLabel?: string;
84
+ renderItemContent?: (
85
+ item: FileDropPresentationItem,
86
+ index: number,
87
+ ) => ReactNode;
88
+ };
89
+
78
90
  type FileDropControlSharedProps<AssetKind extends string> = {
91
+ collectionActions?: FileDropCollectionActions;
79
92
  onClear?: () => void;
80
93
  onItemRemove?: (
81
94
  item: FileDropPresentationItem<AssetKind>,
@@ -108,27 +121,28 @@ type FileDropPresentationControlProps<
108
121
  previews?: never;
109
122
  };
110
123
 
111
- type FileDropLegacyControlProps = FileDropControlSharedProps<FileDropAssetKind> & {
112
- accept?: string;
113
- assetKind?: FileDropAssetKind;
114
- multiple?: boolean;
115
- onFileSelect?: (file: File) => void;
116
- onFilesSelect?: (files: File[]) => void;
117
- onFolderSelect?: never;
118
- onAction?: never;
119
- onItemRemove?: never;
120
- onItemSelect?: never;
121
- onItemsReorder?: never;
122
- onPreviewRemove?: (preview: FileDropPreview, index: number) => void;
123
- onPreviewReorder?: (orderedPreviews: FileDropPreview[]) => void;
124
- onPreviewTransform?: (
125
- preview: FileDropPreview,
126
- operation: FileDropImageTransformOperation,
127
- ) => void;
128
- presentation?: undefined;
129
- preview?: FileDropPreview;
130
- previews?: readonly FileDropPreview[];
131
- };
124
+ type FileDropLegacyControlProps =
125
+ FileDropControlSharedProps<FileDropAssetKind> & {
126
+ accept?: string;
127
+ assetKind?: FileDropAssetKind;
128
+ multiple?: boolean;
129
+ onFileSelect?: (file: File) => void;
130
+ onFilesSelect?: (files: File[]) => void;
131
+ onFolderSelect?: never;
132
+ onAction?: never;
133
+ onItemRemove?: never;
134
+ onItemSelect?: never;
135
+ onItemsReorder?: never;
136
+ onPreviewRemove?: (preview: FileDropPreview, index: number) => void;
137
+ onPreviewReorder?: (orderedPreviews: FileDropPreview[]) => void;
138
+ onPreviewTransform?: (
139
+ preview: FileDropPreview,
140
+ operation: FileDropImageTransformOperation,
141
+ ) => void;
142
+ presentation?: undefined;
143
+ preview?: FileDropPreview;
144
+ previews?: readonly FileDropPreview[];
145
+ };
132
146
 
133
147
  export type FileDropControlProps<
134
148
  AssetKind extends string = FileDropAssetKind,
@@ -3,6 +3,7 @@
3
3
  export { FileDropControl } from "./file-drop-control";
4
4
  export type {
5
5
  FileDropAssetKind,
6
+ FileDropCollectionActions,
6
7
  FileDropControlProps,
7
8
  FileDropImageSize,
8
9
  FileDropImageTransform,
@@ -89,10 +89,12 @@ export type {
89
89
  export {
90
90
  CollectionActionsControl,
91
91
  CollectionActionsControl as CollectionActions,
92
+ CollectionItemGroups,
92
93
  } from "./collection-actions";
93
94
  export type {
94
95
  CollectionActionsControlProps,
95
96
  CollectionActionsControlProps as CollectionActionsProps,
97
+ CollectionItemGroupsProps,
96
98
  } from "./collection-actions";
97
99
  export { createControlHistoryGroupId } from "./control-types";
98
100
  export type {
@@ -118,6 +120,7 @@ export type {
118
120
  export { FileDropControl, FileDropControl as FileDrop } from "./file-drop";
119
121
  export type {
120
122
  FileDropAssetKind,
123
+ FileDropCollectionActions,
121
124
  FileDropControlProps,
122
125
  FileDropControlProps as FileDropProps,
123
126
  FileDropImageSize,
@@ -52,7 +52,7 @@ export function RangeSliderControl({
52
52
  const liveHistoryGroupRef = React.useRef<string | null>(null);
53
53
  const resolvedValueLabel = valueLabel
54
54
  ? applySliderValueLabelUnit(valueLabel, unit)
55
- : formatRangeSliderValue(rangeValue, unit);
55
+ : formatRangeSliderValue(rangeValue, step, unit);
56
56
 
57
57
  React.useEffect(() => {
58
58
  setRangeValue(value);
@@ -0,0 +1,14 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { formatRangeSliderValue } from "./range-slider-value";
4
+
5
+ describe("formatRangeSliderValue", () => {
6
+ it("preserves the precision declared by the slider step", () => {
7
+ expect(formatRangeSliderValue([0.25, 0.77], 0.01)).toBe("0.25 – 0.77");
8
+ expect(formatRangeSliderValue([2.5, 7.5], 0.1, "%")).toBe("2.5% – 7.5%");
9
+ });
10
+
11
+ it("keeps integer ranges compact", () => {
12
+ expect(formatRangeSliderValue([20, 80], 1)).toBe("20 – 80");
13
+ });
14
+ });
@@ -1,4 +1,4 @@
1
- import { applySliderValueLabelUnit } from "../slider/slider-value";
1
+ import { formatSliderValueWithUnit } from "../slider/slider-value";
2
2
 
3
3
  const signedNumberPattern = "[-−]?\\d+(?:[.,]\\d+)?";
4
4
  const rangePairPattern = new RegExp(
@@ -8,10 +8,11 @@ const rangePairPattern = new RegExp(
8
8
 
9
9
  export function formatRangeSliderValue(
10
10
  value: readonly number[],
11
+ step: number,
11
12
  unit?: string,
12
13
  ): string {
13
14
  const formatValue = (item: number): string =>
14
- applySliderValueLabelUnit(String(Math.round(item)), unit);
15
+ formatSliderValueWithUnit(item, step, unit);
15
16
 
16
17
  if (value.length >= 2 && value[0] === value[1]) {
17
18
  return formatValue(value[0] ?? 0);
@@ -1,166 +0,0 @@
1
- import type { ResolvedToolcraftAppSchema } from "../schema/types";
2
- import type { ToolcraftState } from "../state/types";
3
- import {
4
- resolveToolcraftExportFrame,
5
- ToolcraftSceneExportError,
6
- validateToolcraftArtifactSize,
7
- type ToolcraftExportFrame,
8
- } from "./export-frame";
9
- import {
10
- getToolcraftImageExportSize,
11
- type ToolcraftImageExportResolution,
12
- } from "./export-sizing";
13
-
14
- export * from "./export-sizing";
15
-
16
- export type ToolcraftExportFormat = "png" | "video";
17
-
18
- export type ToolcraftExportBackgroundOptions = {
19
- format: ToolcraftExportFormat;
20
- schema: ResolvedToolcraftAppSchema;
21
- };
22
-
23
- export type ToolcraftPreviewBackgroundOptions = {
24
- includeBackgroundTarget?: string;
25
- state: ToolcraftState;
26
- };
27
-
28
- export type ToolcraftPngRenderContext = {
29
- canvas: HTMLCanvasElement;
30
- context: CanvasRenderingContext2D;
31
- cssHeight: number;
32
- cssWidth: number;
33
- frame: ToolcraftExportFrame;
34
- includeBackground: boolean;
35
- pixelHeight: number;
36
- pixelRatio: number;
37
- pixelWidth: number;
38
- };
39
-
40
- export type ToolcraftPngExportCanvasOptions = {
41
- background?: string;
42
- canvasFactory?: () => HTMLCanvasElement;
43
- devicePixelRatio?: number;
44
- frame?: ToolcraftExportFrame;
45
- includeBackground?: boolean;
46
- render: (context: ToolcraftPngRenderContext) => void;
47
- resolution?: ToolcraftImageExportResolution | string;
48
- state: ToolcraftState;
49
- };
50
-
51
- export function shouldIncludeToolcraftExportBackground({
52
- format,
53
- schema,
54
- }: ToolcraftExportBackgroundOptions): boolean {
55
- if (format === "video") {
56
- return true;
57
- }
58
-
59
- return schema.export.png.background !== "transparent";
60
- }
61
-
62
- export function shouldIncludeToolcraftPreviewBackground({
63
- includeBackgroundTarget = "export.includeBackground",
64
- state,
65
- }: ToolcraftPreviewBackgroundOptions): boolean {
66
- if (state.canvas.mode === "infinite") {
67
- return false;
68
- }
69
-
70
- const includeBackgroundValue = state.values[includeBackgroundTarget];
71
-
72
- if (typeof includeBackgroundValue === "boolean") {
73
- return includeBackgroundValue;
74
- }
75
-
76
- if (typeof includeBackgroundValue === "string") {
77
- const normalizedValue = includeBackgroundValue.trim().toLowerCase();
78
-
79
- if (
80
- normalizedValue === "false" ||
81
- normalizedValue === "off" ||
82
- normalizedValue === "no" ||
83
- normalizedValue === "transparent" ||
84
- normalizedValue === "exclude"
85
- ) {
86
- return false;
87
- }
88
-
89
- if (
90
- normalizedValue === "true" ||
91
- normalizedValue === "on" ||
92
- normalizedValue === "yes" ||
93
- normalizedValue === "include"
94
- ) {
95
- return true;
96
- }
97
- }
98
-
99
- return true;
100
- }
101
-
102
- export function createToolcraftPngExportCanvas({
103
- background = "#000000",
104
- canvasFactory = () => document.createElement("canvas"),
105
- devicePixelRatio,
106
- frame,
107
- includeBackground: includeBackgroundOverride,
108
- render,
109
- resolution,
110
- state,
111
- }: ToolcraftPngExportCanvasOptions): HTMLCanvasElement {
112
- const canvas = canvasFactory();
113
- const frameResult = frame
114
- ? { frame, ok: true as const }
115
- : resolveToolcraftExportFrame(state, null);
116
- if (!frameResult.ok) throw new ToolcraftSceneExportError(frameResult);
117
- const resolvedFrame = frameResult.frame;
118
- const { height, pixelRatio, width } = getToolcraftImageExportSize({
119
- devicePixelRatio,
120
- frame: resolvedFrame,
121
- resolution,
122
- state,
123
- });
124
- const artifactSize = validateToolcraftArtifactSize({ height, width });
125
- if (!artifactSize.ok) throw new ToolcraftSceneExportError(artifactSize);
126
- const includeBackground =
127
- includeBackgroundOverride ??
128
- shouldIncludeToolcraftExportBackground({
129
- format: "png",
130
- schema: state.schema,
131
- });
132
-
133
- canvas.width = width;
134
- canvas.height = height;
135
-
136
- const context = canvas.getContext("2d");
137
-
138
- if (!context) {
139
- throw new Error("Toolcraft PNG export requires a 2D canvas context.");
140
- }
141
-
142
- context.save();
143
- context.clearRect(0, 0, width, height);
144
-
145
- if (includeBackground) {
146
- context.fillStyle = background;
147
- context.fillRect(0, 0, width, height);
148
- }
149
-
150
- context.scale(pixelRatio, pixelRatio);
151
- context.translate(-resolvedFrame.x, -resolvedFrame.y);
152
- render({
153
- canvas,
154
- context,
155
- cssHeight: resolvedFrame.height,
156
- cssWidth: resolvedFrame.width,
157
- frame: resolvedFrame,
158
- includeBackground,
159
- pixelHeight: height,
160
- pixelRatio,
161
- pixelWidth: width,
162
- });
163
- context.restore();
164
-
165
- return canvas;
166
- }
@@ -1,60 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
-
3
- import { areToolcraftConditionsProvablyExclusive } from "./condition-exclusivity";
4
-
5
- describe("Toolcraft condition exclusivity", () => {
6
- it("proves disjoint finite value gates", () => {
7
- expect(
8
- areToolcraftConditionsProvablyExclusive(
9
- { equals: "first", target: "model.active" },
10
- { equals: "second", target: "model.active" },
11
- ),
12
- ).toBe(true);
13
- expect(
14
- areToolcraftConditionsProvablyExclusive(
15
- { oneOf: ["first", "second"], target: "model.active" },
16
- { equals: "second", target: "model.active" },
17
- ),
18
- ).toBe(false);
19
- expect(
20
- areToolcraftConditionsProvablyExclusive(
21
- { notEquals: "hidden", target: "model.active" },
22
- { equals: "second", target: "model.active" },
23
- ),
24
- ).toBe(false);
25
- });
26
-
27
- it("proves non-overlapping numeric intervals without guessing across targets", () => {
28
- expect(
29
- areToolcraftConditionsProvablyExclusive(
30
- { lessThan: 0, target: "model.index" },
31
- { greaterThanOrEqual: 0, target: "model.index" },
32
- ),
33
- ).toBe(true);
34
- expect(
35
- areToolcraftConditionsProvablyExclusive(
36
- { equals: "first", target: "first.mode" },
37
- { equals: "second", target: "second.mode" },
38
- ),
39
- ).toBe(false);
40
- });
41
-
42
- it("stays conservative for primitive JSON collisions and invalid numeric bounds", () => {
43
- expect(
44
- areToolcraftConditionsProvablyExclusive(
45
- { equals: Number.NaN, target: "model.mode" },
46
- { notEquals: null, target: "model.mode" },
47
- ),
48
- ).toBe(false);
49
- expect(
50
- areToolcraftConditionsProvablyExclusive(
51
- {
52
- equals: 1,
53
- greaterThan: Number.NaN,
54
- target: "model.mode",
55
- },
56
- { equals: 1, target: "model.mode" },
57
- ),
58
- ).toBe(false);
59
- });
60
- });
@@ -1,221 +0,0 @@
1
- import type { ToolcraftControlConditionSchema } from "@repo/toolcraft-runtime";
2
-
3
- function valuesEqual(left: unknown, right: unknown): boolean {
4
- if (Object.is(left, right)) {
5
- return true;
6
- }
7
-
8
- if (
9
- (typeof left !== "object" || left === null) &&
10
- (typeof right !== "object" || right === null)
11
- ) {
12
- return false;
13
- }
14
-
15
- try {
16
- return JSON.stringify(left) === JSON.stringify(right);
17
- } catch {
18
- return false;
19
- }
20
- }
21
-
22
- function readComparableNumber(value: unknown): number | null {
23
- if (typeof value === "number" && Number.isFinite(value)) {
24
- return value;
25
- }
26
-
27
- if (typeof value === "string") {
28
- const numberValue = Number(value.trim());
29
-
30
- return Number.isFinite(numberValue) ? numberValue : null;
31
- }
32
-
33
- return null;
34
- }
35
-
36
- function conditionMatchesValue(
37
- condition: ToolcraftControlConditionSchema,
38
- value: unknown,
39
- ): boolean {
40
- const matches: boolean[] = [];
41
-
42
- if ("equals" in condition) {
43
- matches.push(valuesEqual(value, condition.equals));
44
- }
45
- if ("notEquals" in condition) {
46
- matches.push(!valuesEqual(value, condition.notEquals));
47
- }
48
- if (condition.oneOf) {
49
- matches.push(condition.oneOf.some((item) => valuesEqual(value, item)));
50
- }
51
- if (condition.notOneOf) {
52
- matches.push(!condition.notOneOf.some((item) => valuesEqual(value, item)));
53
- }
54
-
55
- const numberValue = readComparableNumber(value);
56
- for (const [expected, compare] of [
57
- [condition.greaterThan, (left: number, right: number) => left > right],
58
- [
59
- condition.greaterThanOrEqual,
60
- (left: number, right: number) => left >= right,
61
- ],
62
- [condition.lessThan, (left: number, right: number) => left < right],
63
- [
64
- condition.lessThanOrEqual,
65
- (left: number, right: number) => left <= right,
66
- ],
67
- ] as const) {
68
- if (typeof expected === "number" && Number.isFinite(expected)) {
69
- matches.push(numberValue !== null && compare(numberValue, expected));
70
- }
71
- }
72
-
73
- return matches.length > 0 && matches.every(Boolean);
74
- }
75
-
76
- function getFiniteConditionValues(
77
- condition: ToolcraftControlConditionSchema,
78
- ): readonly unknown[] | null {
79
- const candidates =
80
- "equals" in condition
81
- ? [condition.equals]
82
- : condition.oneOf
83
- ? [...condition.oneOf]
84
- : null;
85
-
86
- return candidates?.filter((value) => conditionMatchesValue(condition, value)) ?? null;
87
- }
88
-
89
- type NumericBoundary = {
90
- inclusive: boolean;
91
- value: number;
92
- };
93
-
94
- type NumericInterval = {
95
- lower: NumericBoundary | null;
96
- upper: NumericBoundary | null;
97
- };
98
-
99
- function stricterLowerBoundary(
100
- current: NumericBoundary | null,
101
- candidate: NumericBoundary,
102
- ): NumericBoundary {
103
- if (
104
- !current ||
105
- candidate.value > current.value ||
106
- (candidate.value === current.value && !candidate.inclusive)
107
- ) {
108
- return candidate;
109
- }
110
-
111
- return current;
112
- }
113
-
114
- function stricterUpperBoundary(
115
- current: NumericBoundary | null,
116
- candidate: NumericBoundary,
117
- ): NumericBoundary {
118
- if (
119
- !current ||
120
- candidate.value < current.value ||
121
- (candidate.value === current.value && !candidate.inclusive)
122
- ) {
123
- return candidate;
124
- }
125
-
126
- return current;
127
- }
128
-
129
- function getNumericInterval(
130
- condition: ToolcraftControlConditionSchema,
131
- ): NumericInterval | null {
132
- let lower: NumericBoundary | null = null;
133
- let upper: NumericBoundary | null = null;
134
-
135
- if (condition.greaterThan !== undefined) {
136
- lower = stricterLowerBoundary(lower, {
137
- inclusive: false,
138
- value: condition.greaterThan,
139
- });
140
- }
141
- if (condition.greaterThanOrEqual !== undefined) {
142
- lower = stricterLowerBoundary(lower, {
143
- inclusive: true,
144
- value: condition.greaterThanOrEqual,
145
- });
146
- }
147
- if (condition.lessThan !== undefined) {
148
- upper = stricterUpperBoundary(upper, {
149
- inclusive: false,
150
- value: condition.lessThan,
151
- });
152
- }
153
- if (condition.lessThanOrEqual !== undefined) {
154
- upper = stricterUpperBoundary(upper, {
155
- inclusive: true,
156
- value: condition.lessThanOrEqual,
157
- });
158
- }
159
-
160
- return lower || upper ? { lower, upper } : null;
161
- }
162
-
163
- function intervalEndsBefore(
164
- upper: NumericBoundary | null,
165
- lower: NumericBoundary | null,
166
- ): boolean {
167
- if (!upper || !lower) {
168
- return false;
169
- }
170
-
171
- return (
172
- upper.value < lower.value ||
173
- (upper.value === lower.value && (!upper.inclusive || !lower.inclusive))
174
- );
175
- }
176
-
177
- export function areToolcraftConditionsProvablyExclusive(
178
- left: ToolcraftControlConditionSchema,
179
- right: ToolcraftControlConditionSchema,
180
- ): boolean {
181
- if (left.target !== right.target) {
182
- return false;
183
- }
184
-
185
- const leftValues = getFiniteConditionValues(left);
186
- if (
187
- leftValues &&
188
- leftValues.every((value) => !conditionMatchesValue(right, value))
189
- ) {
190
- return true;
191
- }
192
-
193
- const rightValues = getFiniteConditionValues(right);
194
- if (
195
- rightValues &&
196
- rightValues.every((value) => !conditionMatchesValue(left, value))
197
- ) {
198
- return true;
199
- }
200
-
201
- const leftInterval = getNumericInterval(left);
202
- const rightInterval = getNumericInterval(right);
203
-
204
- return Boolean(
205
- leftInterval &&
206
- rightInterval &&
207
- (intervalEndsBefore(leftInterval.upper, rightInterval.lower) ||
208
- intervalEndsBefore(rightInterval.upper, leftInterval.lower)),
209
- );
210
- }
211
-
212
- export function areToolcraftConditionSetsProvablyExclusive(
213
- left: readonly ToolcraftControlConditionSchema[],
214
- right: readonly ToolcraftControlConditionSchema[],
215
- ): boolean {
216
- return left.some((leftCondition) =>
217
- right.some((rightCondition) =>
218
- areToolcraftConditionsProvablyExclusive(leftCondition, rightCondition),
219
- ),
220
- );
221
- }