@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.
- package/package.json +1 -1
- package/src/generate-demand-only-lifecycle.test.mjs +9 -1
- package/src/generate-performance-iteration-execution.test.mjs +3 -3
- package/src/generate-test-delivery-architecture-assertions.mjs +11 -73
- package/src/generate-test-demand-only-lifecycle.mjs +34 -36
- package/src/generate-test-dependency-sandbox.mjs +4 -1
- package/src/generate-test-doc-assertions.mjs +55 -53
- package/src/generate-test-doc-assertions.test.mjs +1 -1
- package/src/generate-test-doc-policy-assertions.mjs +1 -1
- package/src/generate-test-export-doc-assertions.mjs +53 -0
- package/src/generate-test-file-assertions.mjs +51 -8
- package/src/generate-test-integrity-assertions.mjs +5 -2
- package/src/generate-test-integrity-manifest-assertions.mjs +16 -5
- package/src/generate-test-integrity-ownership-assertions.mjs +36 -4
- package/src/generate-test-package-assertions.mjs +4 -0
- package/src/generate-test-product-fixture.mjs +1 -1
- package/src/generate-test-product-fixture.test.mjs +35 -38
- package/src/generate-test-product-iteration.mjs +0 -1
- package/src/generate-test-product-iteration.test.mjs +0 -1
- package/src/generate-test-runtime-boundary-assertions.mjs +20 -0
- package/src/generate-test-standalone-assertions.mjs +0 -16
- package/src/generate-test-standalone-delivery-stages.mjs +2 -86
- package/src/generate.test.mjs +4 -0
- package/src/generated-integrity-manifest.test.mjs +5 -2
- package/src/generated-source-policy.test.mjs +0 -4
- package/src/package-json.mjs +5 -0
- package/src/package-json.test.mjs +21 -0
- package/src/package-manager.mjs +2 -0
- package/src/package-manager.test.mjs +8 -0
- package/src/packaged-template-fallback-helpers.mjs +254 -0
- package/src/packaged-template-fallback.test.mjs +121 -46
- package/src/packaged-template-runtime-assertions.mjs +150 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +18 -3
- package/templates/runtime/contracts/component-contracts.choices.ts +8 -3
- package/templates/runtime/contracts/component-contracts.inputs.ts +2 -1
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +18 -4
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +7 -4
- package/templates/runtime/contracts/component-contracts.visual.test.ts +20 -0
- package/templates/runtime/contracts/component-contracts.visual.ts +4 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +18 -12
- package/templates/runtime/contracts/decision-contracts.ts +4 -4
- package/templates/runtime/contracts/performance-verification-policy.test.ts +12 -12
- package/templates/runtime/contracts/performance-verification-policy.ts +8 -8
- package/templates/runtime/export/artifact-download.ts +1 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +2 -15
- package/templates/runtime/export/artifact-frame-state.ts +16 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +3 -3
- package/templates/runtime/export/artifact-scene-frame.ts +3 -3
- package/templates/runtime/export/export-error.ts +5 -0
- package/templates/runtime/export/export-renderer-coverage.ts +54 -0
- package/templates/runtime/export/image-artifact-export.ts +2 -2
- package/templates/runtime/export/index.ts +13 -0
- package/templates/runtime/export/product-export-renderer.test.ts +38 -4
- package/templates/runtime/export/product-export-renderer.ts +0 -41
- package/templates/runtime/export/product-svg-export-renderer.ts +21 -0
- package/templates/runtime/export/svg-artifact-export.test.ts +98 -0
- package/templates/runtime/export/svg-artifact-export.ts +120 -0
- package/templates/runtime/export/svg-document.test.ts +221 -0
- package/templates/runtime/export/svg-document.ts +400 -0
- package/templates/runtime/export/svg-policy.ts +47 -0
- package/templates/runtime/index.ts +1 -0
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +10 -0
- package/templates/runtime/react/app-shell/settings-transfer.test.ts +21 -0
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +46 -1
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +7 -2
- package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +30 -0
- package/templates/runtime/react/canvas/canvas-shell-pinch-interactions.test.tsx +155 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +1 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +16 -5
- package/templates/runtime/react/canvas/canvas-viewport-geometry.ts +133 -0
- package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +285 -36
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-applicability-layout.test.tsx +134 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +16 -1
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.render-isolation.test.tsx +2 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +39 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +3 -3
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +1 -4
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +2 -2
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +6 -6
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +2 -2
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +40 -11
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +31 -2
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +4 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +2 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +2 -52
- package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +1 -9
- package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +7 -2
- package/templates/runtime/react/orientation-gizmo/orientation-gizmo-math.ts +9 -69
- package/templates/runtime/schema/artifact-export-actions.test.ts +47 -0
- package/templates/runtime/schema/artifact-export-actions.ts +49 -0
- package/templates/runtime/schema/types.ts +1 -0
- package/templates/runtime/state/canvas-background-state.ts +1 -16
- package/templates/runtime/state/canvas-state.ts +32 -20
- package/templates/runtime/state/control-value-codecs.test.ts +98 -0
- package/templates/runtime/state/control-value-codecs.ts +700 -0
- package/templates/runtime/state/control-value-normalization.test.ts +1 -1
- package/templates/runtime/state/control-value-normalization.ts +127 -135
- package/templates/runtime/state/controls-reducer.ts +26 -3
- package/templates/runtime/state/create-template-state.test.ts +30 -0
- package/templates/runtime/state/create-template-state.ts +52 -31
- package/templates/runtime/state/orientation-pose.ts +80 -0
- package/templates/runtime/state/persistence-control-values.test.ts +59 -0
- package/templates/runtime/state/reducer-controls.test.ts +45 -0
- package/templates/runtime/state/reducer-media-reset.test.ts +1 -1
- package/templates/runtime/state/reducer-timeline.test.ts +70 -0
- package/templates/runtime/state/timeline-reducer.ts +40 -2
- package/templates/runtime/testing/performance-schema-queries.ts +2 -2
- package/templates/starter/AGENTS.md +21 -22
- package/templates/starter/docs/toolcraft/README.md +6 -6
- package/templates/starter/docs/toolcraft/acceptance-testing.md +20 -20
- package/templates/starter/docs/toolcraft/agent-worklog.md +88 -1
- package/templates/starter/docs/toolcraft/assembly-workflow.md +7 -6
- package/templates/starter/docs/toolcraft/component-rules.md +2 -2
- package/templates/starter/docs/toolcraft/core/layout.md +6 -1
- package/templates/starter/docs/toolcraft/core/media-upload.md +1 -1
- package/templates/starter/docs/toolcraft/core/performance.md +8 -10
- package/templates/starter/docs/toolcraft/core/reference-study.md +80 -19
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +2 -1
- package/templates/starter/docs/toolcraft/core/setup-export.md +43 -13
- package/templates/starter/docs/toolcraft/decision-contract.md +2 -2
- package/templates/starter/docs/toolcraft/performance.md +8 -10
- package/templates/starter/docs/toolcraft/renderer-technique.md +2 -2
- package/templates/starter/docs/toolcraft/schema-reference.md +8 -8
- package/templates/starter/docs/toolcraft/workflow.md +14 -14
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +38 -0
- package/templates/starter/e2e/app-browser-motion-reference-requirements.spec.ts +411 -0
- package/templates/starter/e2e/app-browser-proof-session.spec.ts +85 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +62 -0
- package/templates/starter/e2e/app-browser-selection-scope-evidence.spec.ts +137 -0
- package/templates/starter/e2e/browser-infinity-canvas-svg-evidence.ts +42 -0
- package/templates/starter/e2e/browser-layer-evidence-helpers.ts +15 -36
- package/templates/starter/e2e/browser-product-raster-snapshot.ts +213 -0
- package/templates/starter/e2e/browser-proof-session.ts +43 -15
- package/templates/starter/e2e/browser-proof-surface-action.ts +79 -0
- package/templates/starter/e2e/browser-proof-types.ts +15 -0
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +22 -6
- package/templates/starter/e2e/browser-selection-scope-evidence.ts +269 -0
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +97 -0
- package/templates/starter/e2e/browser-svg-export-evidence.spec.ts +79 -0
- package/templates/starter/e2e/browser-svg-export-evidence.ts +152 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +70 -0
- package/templates/starter/e2e/product-observable-helpers.ts +8 -129
- package/templates/starter/e2e/svg-artifact-inspection.spec.ts +136 -0
- package/templates/starter/e2e/svg-artifact-inspection.ts +331 -0
- package/templates/starter/e2e/svg-download-test-fixtures.ts +34 -0
- package/templates/starter/e2e/toolcraft-delivery-catalog-reporter.ts +198 -15
- package/templates/starter/e2e/toolcraft-feature-verification-reporter.spec.ts +149 -0
- package/templates/starter/e2e/toolcraft-feature-verification-reporter.ts +223 -0
- package/templates/starter/package.json +2 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
- package/templates/starter/scripts/create-toolcraft-motion-reference-study.mjs +233 -0
- package/templates/starter/scripts/create-toolcraft-motion-reference-study.test.mjs +459 -0
- package/templates/starter/scripts/playwright-test-title-selection.d.mts +45 -0
- package/templates/starter/scripts/run-browser-performance-test-helpers.mjs +0 -27
- package/templates/starter/scripts/run-browser-performance.mjs +0 -6
- package/templates/starter/scripts/run-browser-performance.test.mjs +5 -13
- package/templates/starter/scripts/run-delivery-verification-test-helpers.mjs +0 -34
- package/templates/starter/scripts/run-delivery-verification.test.mjs +135 -31
- package/templates/starter/scripts/run-feature-verification.mjs +212 -0
- package/templates/starter/scripts/run-feature-verification.test.mjs +226 -0
- package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.mjs +21 -8
- package/templates/starter/scripts/toolcraft-checkpoint-delivery-state.test.mjs +32 -92
- package/templates/starter/scripts/toolcraft-checkpoint-transaction.mjs +28 -6
- package/templates/starter/scripts/toolcraft-checkpoint-transaction.test.mjs +8 -63
- package/templates/starter/scripts/toolcraft-delivery-anchor.mjs +28 -8
- package/templates/starter/scripts/toolcraft-delivery-anchor.test.mjs +50 -61
- package/templates/starter/scripts/toolcraft-delivery-architecture-inventory.mjs +0 -4
- package/templates/starter/scripts/toolcraft-delivery-architecture-policy.mjs +0 -1
- package/templates/starter/scripts/toolcraft-delivery-evidence.test.mjs +2 -3
- package/templates/starter/scripts/toolcraft-delivery-executor.mjs +5 -1
- package/templates/starter/scripts/toolcraft-delivery-executor.test.mjs +5 -12
- package/templates/starter/scripts/toolcraft-delivery-functional-context.d.mts +1 -48
- package/templates/starter/scripts/toolcraft-delivery-functional-context.mjs +2 -30
- package/templates/starter/scripts/toolcraft-delivery-functional-context.test.mjs +4 -166
- package/templates/starter/scripts/toolcraft-delivery-functional-initial.test.mjs +4 -20
- package/templates/starter/scripts/toolcraft-delivery-lifecycle.mjs +43 -192
- package/templates/starter/scripts/toolcraft-delivery-performance-iteration-lifecycle.test.mjs +79 -440
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +102 -297
- package/templates/starter/scripts/toolcraft-delivery-plan-construction.mjs +46 -97
- package/templates/starter/scripts/toolcraft-delivery-plan-test-helpers.mjs +125 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-validation.test.mjs +58 -0
- package/templates/starter/scripts/toolcraft-delivery-plan.d.mts +19 -31
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +254 -252
- package/templates/starter/scripts/toolcraft-delivery-plan.test.mjs +29 -457
- package/templates/starter/scripts/toolcraft-delivery-receipt-performance.test.mjs +1 -1
- package/templates/starter/scripts/toolcraft-delivery-receipt-strictness.test.mjs +3 -72
- package/templates/starter/scripts/toolcraft-delivery-receipt-test-helpers.mjs +7 -36
- package/templates/starter/scripts/toolcraft-delivery-receipt.d.mts +3 -5
- package/templates/starter/scripts/toolcraft-delivery-receipt.mjs +15 -31
- package/templates/starter/scripts/toolcraft-delivery-receipt.test.mjs +28 -20
- package/templates/starter/scripts/toolcraft-delivery-receipt.types.test.mts +22 -30
- package/templates/starter/scripts/toolcraft-feature-verification-plan.d.mts +20 -0
- package/templates/starter/scripts/toolcraft-feature-verification-plan.mjs +146 -0
- package/templates/starter/scripts/toolcraft-feature-verification-plan.test.mjs +96 -0
- package/templates/starter/scripts/toolcraft-functional-proof-model.d.mts +3 -18
- package/templates/starter/scripts/toolcraft-functional-proof-model.mjs +39 -127
- package/templates/starter/scripts/toolcraft-functional-proof-model.test.mjs +25 -362
- package/templates/starter/scripts/toolcraft-functional-proof-model.types.test.mts +6 -83
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.d.mts +11 -0
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.mjs +61 -0
- package/templates/starter/scripts/toolcraft-functional-proof-primitives.test.mjs +43 -0
- package/templates/starter/scripts/toolcraft-integrity-policy.mjs +13 -0
- package/templates/starter/scripts/toolcraft-integrity-test-utils.mjs +1 -1
- package/templates/starter/scripts/toolcraft-layer-evidence-facade.test.mjs +58 -22
- package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.mjs +111 -0
- package/templates/starter/scripts/toolcraft-motion-reference-analysis-protocol.test.mjs +116 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.d.mts +37 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.mjs +308 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.test.mjs +420 -0
- package/templates/starter/scripts/toolcraft-motion-reference-artifacts.types.test.mts +50 -0
- package/templates/starter/scripts/toolcraft-motion-reference-command-options.mjs +195 -0
- package/templates/starter/scripts/toolcraft-motion-reference-command-options.test.mjs +224 -0
- package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.mjs +122 -0
- package/templates/starter/scripts/toolcraft-motion-reference-contact-sheet.test.mjs +153 -0
- package/templates/starter/scripts/toolcraft-motion-reference-evidence-assembly.mjs +270 -0
- package/templates/starter/scripts/toolcraft-motion-reference-evidence.test.mjs +432 -0
- package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.mjs +275 -0
- package/templates/starter/scripts/toolcraft-motion-reference-ffmpeg-output.test.mjs +294 -0
- package/templates/starter/scripts/toolcraft-motion-reference-group-inventory.mjs +148 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.mjs +101 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-filter-graph.test.mjs +124 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-source.mjs +259 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-source.test.mjs +338 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-timing.mjs +96 -0
- package/templates/starter/scripts/toolcraft-motion-reference-image-timing.test.mjs +81 -0
- package/templates/starter/scripts/toolcraft-motion-reference-lock-recovery.test.mjs +144 -0
- package/templates/starter/scripts/toolcraft-motion-reference-media-source.mjs +165 -0
- package/templates/starter/scripts/toolcraft-motion-reference-media-source.test.mjs +299 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-discovery.test.mjs +142 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-isolation.test.mjs +234 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-schema.mjs +122 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.mjs +89 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal-store.test.mjs +74 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.mjs +264 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-journal.test.mjs +377 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.mjs +254 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-lease.test.mjs +130 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.mjs +128 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication-staging.test.mjs +209 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.fixtures.mjs +88 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.mjs +249 -0
- package/templates/starter/scripts/toolcraft-motion-reference-publication.test.mjs +433 -0
- package/templates/starter/scripts/toolcraft-motion-reference-review-output.mjs +38 -0
- package/templates/starter/scripts/toolcraft-motion-reference-review-output.test.mjs +29 -0
- package/templates/starter/scripts/toolcraft-motion-reference-root-safety.test.mjs +84 -0
- package/templates/starter/scripts/toolcraft-motion-reference-roots.mjs +83 -0
- package/templates/starter/scripts/toolcraft-motion-reference-sampling.mjs +283 -0
- package/templates/starter/scripts/toolcraft-motion-reference-sampling.test.mjs +480 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.mjs +39 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage-registry.test.mjs +59 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage.mjs +71 -0
- package/templates/starter/scripts/toolcraft-motion-reference-stage.test.mjs +61 -0
- package/templates/starter/scripts/toolcraft-motion-review-numeric.mjs +74 -0
- package/templates/starter/scripts/toolcraft-motion-review-numeric.test.mjs +65 -0
- package/templates/starter/scripts/toolcraft-motion-review-partitioning.mjs +268 -0
- package/templates/starter/scripts/toolcraft-motion-review-partitioning.test.mjs +329 -0
- package/templates/starter/scripts/toolcraft-motion-review-protected-units.mjs +120 -0
- package/templates/starter/scripts/toolcraft-motion-review-protected-units.test.mjs +111 -0
- package/templates/starter/scripts/toolcraft-performance-escalation-policy.test.mjs +77 -345
- package/templates/starter/scripts/toolcraft-performance-receipt-validation.test.mjs +19 -21
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +1 -1
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +10 -1
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +5 -1
- package/templates/starter/scripts/toolcraft-product-observable-facade.test.mjs +46 -1
- package/templates/starter/scripts/toolcraft-receipt-boundary.test.mjs +0 -1
- package/templates/starter/scripts/toolcraft-source-inventory.d.mts +5 -0
- package/templates/starter/scripts/toolcraft-source-inventory.mjs +25 -14
- package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +48 -0
- package/templates/starter/scripts/toolcraft-source-ownership.mjs +0 -1
- package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +30 -5
- package/templates/starter/scripts/toolcraft-verification-receipt-test-helpers.mjs +5 -26
- package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +0 -7
- package/templates/starter/scripts/toolcraft-verification-receipt.mjs +3 -47
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +6 -87
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +19 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +107 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +114 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +13 -2
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +110 -0
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +51 -20
- package/templates/starter/src/app/acceptance/canvas-coverage.ts +1 -0
- package/templates/starter/src/app/acceptance/color-bank-labels.ts +11 -15
- package/templates/starter/src/app/acceptance/color-row-grouping.ts +33 -0
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +0 -11
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -3
- package/templates/starter/src/app/acceptance/control-component-rules.ts +0 -10
- package/templates/starter/src/app/acceptance/control-labels.ts +30 -1
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +18 -0
- package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +25 -17
- package/templates/starter/src/app/acceptance/feature-verification-selection.test.ts +295 -0
- package/templates/starter/src/app/acceptance/feature-verification-selection.ts +161 -0
- package/templates/starter/src/app/acceptance/infinity-canvas.ts +10 -0
- package/templates/starter/src/app/acceptance/interaction-ownership-intent.ts +19 -1
- package/templates/starter/src/app/acceptance/interaction-ownership.ts +18 -2
- package/templates/starter/src/app/acceptance/motion-reference-evidence-validation.mjs +65 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence-windows.mjs +301 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence.d.mts +11 -0
- package/templates/starter/src/app/acceptance/motion-reference-evidence.mjs +145 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-behaviors.ts +162 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-coverage.ts +206 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-identity.ts +129 -0
- package/templates/starter/src/app/acceptance/motion-reference-study-partitions.ts +186 -0
- package/templates/starter/src/app/acceptance/motion-reference-study.ts +90 -0
- package/templates/starter/src/app/acceptance/output-export-actions.test.ts +9 -1
- package/templates/starter/src/app/acceptance/output-export-actions.ts +14 -22
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +5 -1
- package/templates/starter/src/app/acceptance/output-export-model.ts +4 -0
- package/templates/starter/src/app/acceptance/output-export.ts +4 -1
- package/templates/starter/src/app/acceptance/reference-study-types.ts +167 -17
- package/templates/starter/src/app/acceptance/runtime-coverage.ts +6 -1
- package/templates/starter/src/app/acceptance/selection-scope.test.ts +200 -0
- package/templates/starter/src/app/acceptance/selection-scope.ts +151 -0
- package/templates/starter/src/app/acceptance/transfer-mode-types.ts +114 -0
- package/templates/starter/src/app/acceptance/types.ts +43 -118
- package/templates/starter/src/app/acceptance/validate-coverage.ts +14 -3
- package/templates/starter/src/app/starter-acceptance-data.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +3 -0
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +81 -8
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.color-row-grouping.test.ts +118 -0
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +1 -0
- package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +78 -3
- package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +77 -1
- package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +74 -3
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +5 -1
- package/templates/starter/src/app/starter-acceptance.image-export-settings.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +19 -3
- package/templates/starter/src/app/starter-acceptance.layers.test.ts +2 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-evidence.test.ts +17 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-identity.test.ts +163 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-mapping.test.ts +133 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-ownership.test.ts +121 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-partitions.test.ts +210 -0
- package/templates/starter/src/app/starter-acceptance.motion-reference-test-utils.ts +313 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +78 -4
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +6 -1
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +18 -1
- package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +123 -2
- package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +8 -0
- package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +7 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +5 -0
- package/templates/starter/src/app/starter-acceptance.ts +34 -8
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +2 -0
- package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +34 -236
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +4 -0
- package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +122 -6
- package/templates/starter/src/app/starter-acceptance.worklog.test.ts +152 -16
- package/templates/starter/src/app/starter-performance.gates.test.ts +20 -18
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +22 -6
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +3 -0
- package/templates/starter/tsconfig.json +1 -0
- package/templates/starter/scripts/toolcraft-browser-impact-selection.mjs +0 -26
- package/templates/starter/scripts/toolcraft-delivery-framework-refresh.test.mjs +0 -141
- package/templates/starter/scripts/toolcraft-delivery-functional-changed.test.mjs +0 -468
- package/templates/starter/scripts/toolcraft-delivery-functional-model-lifecycle.test.mjs +0 -254
- package/templates/starter/scripts/toolcraft-delivery-functional-semantic-regression.test.mjs +0 -135
- package/templates/starter/scripts/toolcraft-delivery-performance-iteration-durability.test.mjs +0 -329
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +0 -430
- package/templates/starter/scripts/toolcraft-delivery-plan-functional-model.test.mjs +0 -358
- package/templates/starter/scripts/toolcraft-functional-proof-regression-fixtures.mjs +0 -298
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.d.mts +0 -62
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.mjs +0 -344
- package/templates/starter/scripts/toolcraft-verification-impact-inventory.test.mjs +0 -204
- package/templates/starter/scripts/toolcraft-verification-impact-performance-candidates.test.mjs +0 -210
- package/templates/starter/scripts/toolcraft-verification-impact-resolution.mjs +0 -344
- package/templates/starter/scripts/toolcraft-verification-impact-resolution.test.mjs +0 -270
- package/templates/starter/scripts/toolcraft-verification-impact-semantic-resolution.test.mjs +0 -449
- package/templates/starter/scripts/toolcraft-verification-impact-support-resolution.test.mjs +0 -195
- package/templates/starter/scripts/toolcraft-verification-impact.d.mts +0 -132
- package/templates/starter/scripts/toolcraft-verification-impact.mjs +0 -169
- package/templates/starter/scripts/toolcraft-verification-impact.test.mjs +0 -300
- package/templates/starter/scripts/toolcraft-verification-input-roles.mjs +0 -197
- package/templates/starter/scripts/toolcraft-verification-input-roles.test.mjs +0 -225
- package/templates/starter/src/app/acceptance/video-reference-study.ts +0 -217
- package/templates/starter/src/app/starter-verification-impact.json +0 -15
|
@@ -6,21 +6,21 @@ export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY = {
|
|
|
6
6
|
complaintRouting:
|
|
7
7
|
"Performance authority and path localization are separate decisions. Classifier output establishes complaint authority only and never path localization. A localized complaint lets the agent select canonical affected paths and run one targeted iteration without asking the user. An ambiguous or unresolved localization requires one user-facing clarification naming visible operations and offering targeted diagnosis or a complete review; never ask the user for internal path ids. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. A broad or honestly unlocalizable problem may justify recommending the complete review immediately, but only the user's explicit request or acceptance authorizes it. A direct request for a complete review runs the full audit without another clarification.",
|
|
8
8
|
deliveryBatch:
|
|
9
|
-
"
|
|
9
|
+
"Run complete protected functional proof once for the first product version. Later ordinary edits are focused development work and never create another aggregate delivery boundary.",
|
|
10
10
|
deliveryCommand:
|
|
11
|
-
"Use
|
|
11
|
+
"Use pnpm verify:delivery for the first complete product proof or one exact request-authorized performance iteration. On a proven product without new performance authority it exits before inventory, tests, build, browser work, or checkpoint writes.",
|
|
12
12
|
demandOnlyPerformance:
|
|
13
13
|
"Only exact request authority can create a performance-iteration plan and run measured targeted performance. Changed files, verification tier, ownership classification, affected pass or path ids, and touched subsystems never authorize measured performance.",
|
|
14
14
|
functionalChangeEvidence:
|
|
15
|
-
"
|
|
15
|
+
"After first delivery, renderer, canvas, animation, export, timeline, layers, canvas.renderScale, bug fixes, and control changes use only focused evidence for the functionality being edited. Those changes never authorize an aggregate functional gate or measured performance.",
|
|
16
16
|
fullAuditDiscovery:
|
|
17
17
|
"The complete performance matrix remains outside conversational delivery. Complaints, repetition, tier, filename, and touched subsystem never launch it automatically. After two consecutive compatible protected performance iterations, the agent must offer a slower complete audit if the user remains unsatisfied; a demonstrably broad or unlocalizable cross-system problem may justify the same offer earlier. An explicit natural-language request for the complete audit, or explicit acceptance of the agent's offer, authorizes the agent acting as operator to run pnpm verify:perf; the user does not need to know the command name. After the audit, repair and rerun failed paths with focused checks, then run the complete matrix only once at the requested certification boundary.",
|
|
18
18
|
performanceIterationDelivery:
|
|
19
19
|
"The runtime request classifier is a tri-state guard, not a replacement for AI semantic judgment: high-confidence runtime complaints, responsiveness optimization, or excessive CPU, GPU, memory, or resource use classify as performance-iteration; high-confidence product motion, speed, freeze, terminology, or locally negated complaint commands classify as ordinary-product-work; ambiguous or unrecognized wording classifies as needs-agent-judgment and the AI decides from the actual user request. Ordinary work is rejected only for a high-confidence performance iteration. Every performance-iteration worklog intent quotes a nontrivial exact raw substring of Request; whitespace and Unicode code units must match before normalized tri-state classification. Invented, whitespace-collapsed, NFKC-equivalent, or mismatched evidence is rejected; high-confidence ordinary evidence is rejected; exact high-confidence performance-iteration evidence, or needs-agent-judgment evidence after semantic resolution, is accepted under agent ownership. Classifier output establishes complaint authority only and never path localization. Each performance iteration requires an exact reachable development fixture and fails with a configuration error instead of falling back to maximum. Only a localized complaint or a post-clarification targeted choice creates performance-iteration intent and one bounded iteration over exact canonical affected paths. Regardless of whether the classifier returned high-confidence performance-iteration or needs-agent-judgment, unresolved localization creates neither performance-iteration intent nor canonical path authority. Each repeated localized request may create one new bounded targeted iteration over its affected paths; repetition alone never expands scope or selects the complete performance matrix, creates or refreshes a durable baseline, or grants full-performance certification authority.",
|
|
20
20
|
functionalInitialDelivery:
|
|
21
21
|
'A functional delivery plan with basis "initial" runs complete functional proof and no measured performance. It preserves any independent full-performance baseline and cannot claim targeted or full performance evidence.',
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
focusedLaterEdits:
|
|
23
|
+
"A proven product has no later functional delivery plan. Ordinary edits run only feature-focused tests or browser inspection chosen from the edited behavior; commit, push, deploy, and preview do not authorize aggregate proof.",
|
|
24
24
|
renderScaleFidelity:
|
|
25
25
|
'canvas.renderScale is visible functional fidelity. Raster products declare typed renderScaleCoverage "selected-backing-pixels" for interaction and steady, plus playback when timeline is enabled, and prove real canvas backing pixels in every declared state. Every measured path in a render-scale-enabled raster product proves actual CSS × devicePixelRatio × 2 backing after each measured phase. Never downsample, stretch a lower-resolution backing canvas, blur output, or clamp the selected render scale to pass a performance budget.',
|
|
26
26
|
} as const;
|
|
@@ -28,8 +28,8 @@ export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY = {
|
|
|
28
28
|
export const TOOLCRAFT_PERFORMANCE_VERIFICATION_LIFECYCLE = {
|
|
29
29
|
delivery: {
|
|
30
30
|
command: "verify:delivery",
|
|
31
|
-
modes: ["functional", "performance-iteration"],
|
|
32
|
-
selectors: "
|
|
31
|
+
modes: ["initial-functional", "performance-iteration"],
|
|
32
|
+
selectors: "initial-complete-or-authority-exact",
|
|
33
33
|
},
|
|
34
34
|
fullPerformance: {
|
|
35
35
|
command: "verify:perf",
|
|
@@ -45,7 +45,7 @@ export const TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY_TEXT = [
|
|
|
45
45
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.demandOnlyPerformance,
|
|
46
46
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.functionalChangeEvidence,
|
|
47
47
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.functionalInitialDelivery,
|
|
48
|
-
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.
|
|
48
|
+
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.focusedLaterEdits,
|
|
49
49
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.renderScaleFidelity,
|
|
50
50
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.performanceIterationDelivery,
|
|
51
51
|
TOOLCRAFT_PERFORMANCE_VERIFICATION_POLICY.fullAuditDiscovery,
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
ToolcraftArtifactExportError,
|
|
7
7
|
} from "./export-error";
|
|
8
8
|
import type { ToolcraftProductExportFrameRenderer } from "./product-export-renderer";
|
|
9
|
+
import { getToolcraftArtifactTimelineProgress } from "./artifact-frame-state";
|
|
9
10
|
|
|
10
11
|
export type ToolcraftArtifactFrameRenderRequest = Readonly<{
|
|
11
12
|
backgroundColor: string;
|
|
@@ -23,20 +24,6 @@ export type ToolcraftArtifactFrameRenderRequest = Readonly<{
|
|
|
23
24
|
state: ToolcraftState;
|
|
24
25
|
}>;
|
|
25
26
|
|
|
26
|
-
function getTimelineProgress(state: ToolcraftState): number {
|
|
27
|
-
if (state.timeline.durationSeconds <= 0) {
|
|
28
|
-
return 0;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
return Math.max(
|
|
32
|
-
0,
|
|
33
|
-
Math.min(
|
|
34
|
-
1,
|
|
35
|
-
state.timeline.currentTimeSeconds / state.timeline.durationSeconds,
|
|
36
|
-
),
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
27
|
export async function renderToolcraftArtifactFrame(
|
|
41
28
|
request: ToolcraftArtifactFrameRenderRequest,
|
|
42
29
|
): Promise<void> {
|
|
@@ -83,7 +70,7 @@ export async function renderToolcraftArtifactFrame(
|
|
|
83
70
|
rendererPipeline: request.rendererPipeline,
|
|
84
71
|
state: request.state,
|
|
85
72
|
timeSeconds: request.state.timeline.currentTimeSeconds,
|
|
86
|
-
timelineProgress:
|
|
73
|
+
timelineProgress: getToolcraftArtifactTimelineProgress(request.state),
|
|
87
74
|
});
|
|
88
75
|
} catch (error) {
|
|
89
76
|
throw normalizeToolcraftExportError(error, {
|
|
@@ -9,6 +9,22 @@ export type ToolcraftVideoArtifactFramePlanEntry = Readonly<{
|
|
|
9
9
|
state: ToolcraftArtifactFrameState;
|
|
10
10
|
}>;
|
|
11
11
|
|
|
12
|
+
export function getToolcraftArtifactTimelineProgress(
|
|
13
|
+
state: ToolcraftState,
|
|
14
|
+
): number {
|
|
15
|
+
if (state.timeline.durationSeconds <= 0) {
|
|
16
|
+
return 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return Math.max(
|
|
20
|
+
0,
|
|
21
|
+
Math.min(
|
|
22
|
+
1,
|
|
23
|
+
state.timeline.currentTimeSeconds / state.timeline.durationSeconds,
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
export function createToolcraftArtifactFrameState(
|
|
13
29
|
baseState: ToolcraftState,
|
|
14
30
|
timeSeconds: number,
|
|
@@ -5,7 +5,7 @@ import { createToolcraftState } from "../state/create-template-state";
|
|
|
5
5
|
import { createToolcraftRuntimeSceneVisibility } from "../scene";
|
|
6
6
|
import { ToolcraftSceneExportError } from "./export-frame";
|
|
7
7
|
import {
|
|
8
|
-
|
|
8
|
+
resolveToolcraftStillArtifactFrame,
|
|
9
9
|
resolveToolcraftVideoArtifactFrame,
|
|
10
10
|
} from "./artifact-scene-frame";
|
|
11
11
|
import { createToolcraftVideoArtifactFramePlan } from "./artifact-frame-state";
|
|
@@ -29,7 +29,7 @@ describe("artifact scene frame", () => {
|
|
|
29
29
|
const boundsProvider = vi.fn(() => []);
|
|
30
30
|
|
|
31
31
|
expect(
|
|
32
|
-
|
|
32
|
+
resolveToolcraftStillArtifactFrame({
|
|
33
33
|
boundsProvider,
|
|
34
34
|
productSceneRequired: true,
|
|
35
35
|
state,
|
|
@@ -73,7 +73,7 @@ describe("artifact scene frame", () => {
|
|
|
73
73
|
|
|
74
74
|
it("fails visibly when an infinite product scene has no bounds provider", () => {
|
|
75
75
|
expect(() =>
|
|
76
|
-
|
|
76
|
+
resolveToolcraftStillArtifactFrame({
|
|
77
77
|
boundsProvider: undefined,
|
|
78
78
|
productSceneRequired: true,
|
|
79
79
|
state: createState("infinite"),
|
|
@@ -21,7 +21,7 @@ type ToolcraftArtifactSceneFrameBaseRequest = Readonly<{
|
|
|
21
21
|
visibility: ToolcraftRuntimeSceneVisibility;
|
|
22
22
|
}>;
|
|
23
23
|
|
|
24
|
-
export type
|
|
24
|
+
export type ToolcraftStillArtifactSceneFrameRequest =
|
|
25
25
|
ToolcraftArtifactSceneFrameBaseRequest &
|
|
26
26
|
Readonly<{ state: ToolcraftState }>;
|
|
27
27
|
|
|
@@ -68,8 +68,8 @@ function isFiniteCanvas(state: ToolcraftState): boolean {
|
|
|
68
68
|
return getToolcraftCanvasFrame(state.canvas).kind === "finite";
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
export function
|
|
72
|
-
request:
|
|
71
|
+
export function resolveToolcraftStillArtifactFrame(
|
|
72
|
+
request: ToolcraftStillArtifactSceneFrameRequest,
|
|
73
73
|
): ToolcraftExportFrame {
|
|
74
74
|
if (isFiniteCanvas(request.state)) {
|
|
75
75
|
return requireFrame(resolveToolcraftExportFrame(request.state, null));
|
|
@@ -8,6 +8,11 @@ export type ToolcraftArtifactExportFailure = Readonly<{
|
|
|
8
8
|
| "invalid-export-setting"
|
|
9
9
|
| "product-frame-render-failed"
|
|
10
10
|
| "runtime-scene-render-failed"
|
|
11
|
+
| "svg-content-empty"
|
|
12
|
+
| "svg-content-invalid"
|
|
13
|
+
| "svg-document-invalid"
|
|
14
|
+
| "svg-render-failed"
|
|
15
|
+
| "svg-serialization-failed"
|
|
11
16
|
| "video-artifact-too-large"
|
|
12
17
|
| "video-encode-failed"
|
|
13
18
|
| "video-encoder-unavailable";
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getToolcraftArtifactExportActions,
|
|
3
|
+
} from "../schema/artifact-export-actions";
|
|
4
|
+
import type { ResolvedToolcraftAppSchema } from "../schema/types";
|
|
5
|
+
import type { ToolcraftProductExportRenderer } from "./product-export-renderer";
|
|
6
|
+
import type { ToolcraftProductSvgExportRenderer } from "./product-svg-export-renderer";
|
|
7
|
+
|
|
8
|
+
export function getToolcraftExportRendererCoverageErrors({
|
|
9
|
+
exportRenderer,
|
|
10
|
+
productSceneRequired,
|
|
11
|
+
schema,
|
|
12
|
+
svgExportRenderer,
|
|
13
|
+
}: Readonly<{
|
|
14
|
+
exportRenderer: ToolcraftProductExportRenderer | undefined;
|
|
15
|
+
productSceneRequired: boolean;
|
|
16
|
+
schema: ResolvedToolcraftAppSchema;
|
|
17
|
+
svgExportRenderer: ToolcraftProductSvgExportRenderer | undefined;
|
|
18
|
+
}>): string[] {
|
|
19
|
+
const errors: string[] = [];
|
|
20
|
+
const exportRoles = new Set(
|
|
21
|
+
getToolcraftArtifactExportActions(schema).map(({ role }) => role),
|
|
22
|
+
);
|
|
23
|
+
const hasRasterExportAction =
|
|
24
|
+
exportRoles.has("export-image") || exportRoles.has("export-video");
|
|
25
|
+
const hasSvgExportAction = exportRoles.has("export-svg");
|
|
26
|
+
|
|
27
|
+
if (hasRasterExportAction && productSceneRequired && !exportRenderer) {
|
|
28
|
+
errors.push("Product-owned image/video export actions require exportRenderer.");
|
|
29
|
+
}
|
|
30
|
+
if (exportRenderer && !productSceneRequired) {
|
|
31
|
+
errors.push("exportRenderer requires a product-owned scene.");
|
|
32
|
+
}
|
|
33
|
+
if (exportRenderer && !hasRasterExportAction) {
|
|
34
|
+
errors.push("exportRenderer requires a typed image or video export action.");
|
|
35
|
+
}
|
|
36
|
+
if (exportRenderer && exportRenderer.baseFileName.trim().length === 0) {
|
|
37
|
+
errors.push("exportRenderer.baseFileName must not be blank.");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (hasSvgExportAction && !svgExportRenderer) {
|
|
41
|
+
errors.push("A typed SVG export action requires svgExportRenderer.");
|
|
42
|
+
}
|
|
43
|
+
if (svgExportRenderer && !hasSvgExportAction) {
|
|
44
|
+
errors.push("svgExportRenderer requires a typed SVG export action.");
|
|
45
|
+
}
|
|
46
|
+
if (
|
|
47
|
+
svgExportRenderer &&
|
|
48
|
+
svgExportRenderer.baseFileName.trim().length === 0
|
|
49
|
+
) {
|
|
50
|
+
errors.push("svgExportRenderer.baseFileName must not be blank.");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return errors;
|
|
54
|
+
}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import type { ToolcraftArtifactExportRequest } from "./artifact-export-request";
|
|
12
12
|
import { resolveToolcraftImageExportSettings } from "./artifact-export-settings";
|
|
13
13
|
import { renderToolcraftArtifactFrame } from "./artifact-frame-renderer";
|
|
14
|
-
import {
|
|
14
|
+
import { resolveToolcraftStillArtifactFrame } from "./artifact-scene-frame";
|
|
15
15
|
import { createToolcraftArtifactFrameState } from "./artifact-frame-state";
|
|
16
16
|
import {
|
|
17
17
|
ToolcraftSceneExportError,
|
|
@@ -80,7 +80,7 @@ export async function exportToolcraftImageArtifact(
|
|
|
80
80
|
request.state,
|
|
81
81
|
request.state.timeline.currentTimeSeconds,
|
|
82
82
|
);
|
|
83
|
-
const frame =
|
|
83
|
+
const frame = resolveToolcraftStillArtifactFrame({
|
|
84
84
|
boundsProvider: request.boundsProvider,
|
|
85
85
|
productSceneRequired: request.productSceneRequired,
|
|
86
86
|
state: frameState,
|
|
@@ -42,3 +42,16 @@ export type {
|
|
|
42
42
|
ToolcraftProductExportFrameRenderer,
|
|
43
43
|
ToolcraftProductExportRenderer,
|
|
44
44
|
} from "./product-export-renderer";
|
|
45
|
+
export type {
|
|
46
|
+
ToolcraftProductSvgExportFrameContext,
|
|
47
|
+
ToolcraftProductSvgExportFrameRenderer,
|
|
48
|
+
ToolcraftProductSvgExportRenderer,
|
|
49
|
+
} from "./product-svg-export-renderer";
|
|
50
|
+
export {
|
|
51
|
+
TOOLCRAFT_FORBIDDEN_SVG_ELEMENTS,
|
|
52
|
+
TOOLCRAFT_SVG_BACKGROUND_ATTRIBUTE,
|
|
53
|
+
TOOLCRAFT_SVG_NAMESPACE,
|
|
54
|
+
TOOLCRAFT_SVG_NON_RENDERING_CONTAINERS,
|
|
55
|
+
TOOLCRAFT_SVG_PRODUCT_SCENE_ATTRIBUTE,
|
|
56
|
+
TOOLCRAFT_SVG_VECTOR_PRIMITIVES,
|
|
57
|
+
} from "./svg-policy";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import { defineToolcraft } from "../schema/define-toolcraft";
|
|
4
|
-
import { getToolcraftExportRendererCoverageErrors } from "./
|
|
4
|
+
import { getToolcraftExportRendererCoverageErrors } from "./export-renderer-coverage";
|
|
5
5
|
|
|
6
|
-
function createSchema(role?: "export-image" | "export-video") {
|
|
6
|
+
function createSchema(role?: "export-image" | "export-svg" | "export-video") {
|
|
7
7
|
return defineToolcraft({
|
|
8
8
|
canvas: { enabled: true },
|
|
9
9
|
panels: role
|
|
@@ -37,8 +37,9 @@ describe("export renderer coverage", () => {
|
|
|
37
37
|
exportRenderer: undefined,
|
|
38
38
|
productSceneRequired: true,
|
|
39
39
|
schema: createSchema("export-image"),
|
|
40
|
+
svgExportRenderer: undefined,
|
|
40
41
|
}),
|
|
41
|
-
).toContain("Product-owned export actions require exportRenderer.");
|
|
42
|
+
).toContain("Product-owned image/video export actions require exportRenderer.");
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
it("allows runtime-only scenes to use runtime composition", () => {
|
|
@@ -47,6 +48,7 @@ describe("export renderer coverage", () => {
|
|
|
47
48
|
exportRenderer: undefined,
|
|
48
49
|
productSceneRequired: false,
|
|
49
50
|
schema: createSchema("export-video"),
|
|
51
|
+
svgExportRenderer: undefined,
|
|
50
52
|
}),
|
|
51
53
|
).toEqual([]);
|
|
52
54
|
});
|
|
@@ -57,6 +59,7 @@ describe("export renderer coverage", () => {
|
|
|
57
59
|
exportRenderer: renderer,
|
|
58
60
|
productSceneRequired: false,
|
|
59
61
|
schema: createSchema("export-image"),
|
|
62
|
+
svgExportRenderer: undefined,
|
|
60
63
|
}),
|
|
61
64
|
).toContain("exportRenderer requires a product-owned scene.");
|
|
62
65
|
expect(
|
|
@@ -64,6 +67,7 @@ describe("export renderer coverage", () => {
|
|
|
64
67
|
exportRenderer: { ...renderer, baseFileName: " " },
|
|
65
68
|
productSceneRequired: true,
|
|
66
69
|
schema: createSchema("export-image"),
|
|
70
|
+
svgExportRenderer: undefined,
|
|
67
71
|
}),
|
|
68
72
|
).toContain("exportRenderer.baseFileName must not be blank.");
|
|
69
73
|
expect(
|
|
@@ -71,7 +75,37 @@ describe("export renderer coverage", () => {
|
|
|
71
75
|
exportRenderer: renderer,
|
|
72
76
|
productSceneRequired: true,
|
|
73
77
|
schema: createSchema(),
|
|
78
|
+
svgExportRenderer: undefined,
|
|
74
79
|
}),
|
|
75
|
-
).toContain("exportRenderer requires a typed export action.");
|
|
80
|
+
).toContain("exportRenderer requires a typed image or video export action.");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("requires SVG actions and renderers to correspond", () => {
|
|
84
|
+
expect(
|
|
85
|
+
getToolcraftExportRendererCoverageErrors({
|
|
86
|
+
exportRenderer: undefined,
|
|
87
|
+
productSceneRequired: false,
|
|
88
|
+
schema: createSchema("export-svg"),
|
|
89
|
+
svgExportRenderer: undefined,
|
|
90
|
+
}),
|
|
91
|
+
).toContain("A typed SVG export action requires svgExportRenderer.");
|
|
92
|
+
|
|
93
|
+
expect(
|
|
94
|
+
getToolcraftExportRendererCoverageErrors({
|
|
95
|
+
exportRenderer: undefined,
|
|
96
|
+
productSceneRequired: false,
|
|
97
|
+
schema: createSchema(),
|
|
98
|
+
svgExportRenderer: renderer,
|
|
99
|
+
}),
|
|
100
|
+
).toContain("svgExportRenderer requires a typed SVG export action.");
|
|
101
|
+
|
|
102
|
+
expect(
|
|
103
|
+
getToolcraftExportRendererCoverageErrors({
|
|
104
|
+
exportRenderer: undefined,
|
|
105
|
+
productSceneRequired: false,
|
|
106
|
+
schema: createSchema("export-svg"),
|
|
107
|
+
svgExportRenderer: { ...renderer, baseFileName: " " },
|
|
108
|
+
}),
|
|
109
|
+
).toContain("svgExportRenderer.baseFileName must not be blank.");
|
|
76
110
|
});
|
|
77
111
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { ToolcraftRendererPipelineClient } from "../rendering";
|
|
2
|
-
import type { ResolvedToolcraftAppSchema } from "../schema/types";
|
|
3
2
|
import type { ToolcraftState } from "../state/types";
|
|
4
3
|
import type { ToolcraftExportFrame } from "./export-frame";
|
|
5
4
|
|
|
@@ -21,43 +20,3 @@ export type ToolcraftProductExportRenderer = Readonly<{
|
|
|
21
20
|
baseFileName: string;
|
|
22
21
|
renderFrame: ToolcraftProductExportFrameRenderer;
|
|
23
22
|
}>;
|
|
24
|
-
|
|
25
|
-
function hasTypedExportAction(schema: ResolvedToolcraftAppSchema): boolean {
|
|
26
|
-
return (schema.panels.controls?.sections ?? []).some((section) =>
|
|
27
|
-
Object.values(section.controls).some((control) =>
|
|
28
|
-
(control.actions ?? []).some(
|
|
29
|
-
(action) =>
|
|
30
|
-
typeof action !== "string" &&
|
|
31
|
-
(action.role === "export-image" || action.role === "export-video"),
|
|
32
|
-
),
|
|
33
|
-
),
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function getToolcraftExportRendererCoverageErrors({
|
|
38
|
-
exportRenderer,
|
|
39
|
-
productSceneRequired,
|
|
40
|
-
schema,
|
|
41
|
-
}: Readonly<{
|
|
42
|
-
exportRenderer: ToolcraftProductExportRenderer | undefined;
|
|
43
|
-
productSceneRequired: boolean;
|
|
44
|
-
schema: ResolvedToolcraftAppSchema;
|
|
45
|
-
}>): string[] {
|
|
46
|
-
const errors: string[] = [];
|
|
47
|
-
const hasExportAction = hasTypedExportAction(schema);
|
|
48
|
-
|
|
49
|
-
if (hasExportAction && productSceneRequired && !exportRenderer) {
|
|
50
|
-
errors.push("Product-owned export actions require exportRenderer.");
|
|
51
|
-
}
|
|
52
|
-
if (exportRenderer && !productSceneRequired) {
|
|
53
|
-
errors.push("exportRenderer requires a product-owned scene.");
|
|
54
|
-
}
|
|
55
|
-
if (exportRenderer && !hasExportAction) {
|
|
56
|
-
errors.push("exportRenderer requires a typed export action.");
|
|
57
|
-
}
|
|
58
|
-
if (exportRenderer && exportRenderer.baseFileName.trim().length === 0) {
|
|
59
|
-
errors.push("exportRenderer.baseFileName must not be blank.");
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return errors;
|
|
63
|
-
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ToolcraftRendererPipelineClient } from "../rendering";
|
|
2
|
+
import type { ToolcraftState } from "../state/types";
|
|
3
|
+
import type { ToolcraftExportFrame } from "./export-frame";
|
|
4
|
+
|
|
5
|
+
export type ToolcraftProductSvgExportFrameContext = Readonly<{
|
|
6
|
+
container: SVGGElement;
|
|
7
|
+
frame: ToolcraftExportFrame;
|
|
8
|
+
rendererPipeline: ToolcraftRendererPipelineClient | null;
|
|
9
|
+
state: Readonly<ToolcraftState>;
|
|
10
|
+
timeSeconds: number;
|
|
11
|
+
timelineProgress: number;
|
|
12
|
+
}>;
|
|
13
|
+
|
|
14
|
+
export type ToolcraftProductSvgExportFrameRenderer = (
|
|
15
|
+
context: ToolcraftProductSvgExportFrameContext,
|
|
16
|
+
) => PromiseLike<void> | void;
|
|
17
|
+
|
|
18
|
+
export type ToolcraftProductSvgExportRenderer = Readonly<{
|
|
19
|
+
baseFileName: string;
|
|
20
|
+
renderFrame: ToolcraftProductSvgExportFrameRenderer;
|
|
21
|
+
}>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { createToolcraftRuntimeSceneVisibility } from "../scene";
|
|
4
|
+
import { defineToolcraft } from "../schema/define-toolcraft";
|
|
5
|
+
import { createToolcraftState } from "../state/create-template-state";
|
|
6
|
+
import type {
|
|
7
|
+
ToolcraftArtifactDownloadRequest,
|
|
8
|
+
ToolcraftArtifactDownloadResult,
|
|
9
|
+
} from "./artifact-download";
|
|
10
|
+
import { exportToolcraftSvgArtifact } from "./svg-artifact-export";
|
|
11
|
+
import { TOOLCRAFT_SVG_NAMESPACE } from "./svg-policy";
|
|
12
|
+
|
|
13
|
+
const visibility = createToolcraftRuntimeSceneVisibility({
|
|
14
|
+
renderDefaultImages: true,
|
|
15
|
+
suppressedModelTargets: [],
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
function createState() {
|
|
19
|
+
return createToolcraftState(
|
|
20
|
+
defineToolcraft({ canvas: { enabled: true }, panels: {} }),
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
describe("exportToolcraftSvgArtifact", () => {
|
|
25
|
+
it("renders current vectors, downloads SVG, and reports monotonic progress", async () => {
|
|
26
|
+
const progress: number[] = [];
|
|
27
|
+
const downloadArtifact = vi.fn(
|
|
28
|
+
(
|
|
29
|
+
_request: ToolcraftArtifactDownloadRequest,
|
|
30
|
+
): ToolcraftArtifactDownloadResult => ({
|
|
31
|
+
fileName: "column-graph.svg",
|
|
32
|
+
}),
|
|
33
|
+
);
|
|
34
|
+
const state = createState();
|
|
35
|
+
|
|
36
|
+
const result = await exportToolcraftSvgArtifact({
|
|
37
|
+
boundsProvider: undefined,
|
|
38
|
+
downloadArtifact,
|
|
39
|
+
productSceneRequired: true,
|
|
40
|
+
rendererPipeline: null,
|
|
41
|
+
reportProgress: (value) => progress.push(value),
|
|
42
|
+
state,
|
|
43
|
+
svgExportRenderer: {
|
|
44
|
+
baseFileName: "column-graph",
|
|
45
|
+
renderFrame: ({ container, frame, state: frameState }) => {
|
|
46
|
+
expect(frameState).not.toBe(state);
|
|
47
|
+
const rect = container.ownerDocument.createElementNS(
|
|
48
|
+
TOOLCRAFT_SVG_NAMESPACE,
|
|
49
|
+
"rect",
|
|
50
|
+
);
|
|
51
|
+
rect.setAttribute("width", String(frame.width));
|
|
52
|
+
rect.setAttribute("height", String(frame.height));
|
|
53
|
+
rect.setAttribute("data-column-graph-background", "true");
|
|
54
|
+
container.append(rect);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
visibility,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
expect(progress).toEqual([0.1, 0.65, 0.9, 1]);
|
|
61
|
+
expect(result).toMatchObject({
|
|
62
|
+
extension: ".svg",
|
|
63
|
+
mediaType: "image/svg+xml",
|
|
64
|
+
vectorElementCount: 1,
|
|
65
|
+
});
|
|
66
|
+
expect(result.byteLength).toBeGreaterThan(0);
|
|
67
|
+
expect(downloadArtifact).toHaveBeenCalledOnce();
|
|
68
|
+
const request = downloadArtifact.mock.calls[0]?.[0];
|
|
69
|
+
expect(request?.extension).toBe(".svg");
|
|
70
|
+
expect(request?.rawBaseFileName).toBe("column-graph");
|
|
71
|
+
expect(request?.blob.type).toBe("image/svg+xml;charset=utf-8");
|
|
72
|
+
await expect(request?.blob.text()).resolves.toContain(
|
|
73
|
+
'data-column-graph-background="true"',
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("normalizes product renderer failures", async () => {
|
|
78
|
+
await expect(
|
|
79
|
+
exportToolcraftSvgArtifact({
|
|
80
|
+
boundsProvider: undefined,
|
|
81
|
+
downloadArtifact: vi.fn(),
|
|
82
|
+
productSceneRequired: false,
|
|
83
|
+
rendererPipeline: null,
|
|
84
|
+
reportProgress: vi.fn(),
|
|
85
|
+
state: createState(),
|
|
86
|
+
svgExportRenderer: {
|
|
87
|
+
baseFileName: "broken",
|
|
88
|
+
renderFrame: () => {
|
|
89
|
+
throw new Error("renderer exploded");
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
visibility,
|
|
93
|
+
}),
|
|
94
|
+
).rejects.toMatchObject({
|
|
95
|
+
feedback: { code: "svg-render-failed" },
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
});
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { ToolcraftRendererPipelineClient } from "../rendering";
|
|
2
|
+
import type {
|
|
3
|
+
ToolcraftProductSceneBoundsProvider,
|
|
4
|
+
ToolcraftRuntimeSceneVisibility,
|
|
5
|
+
} from "../scene";
|
|
6
|
+
import {
|
|
7
|
+
getToolcraftRuntimeBackgroundColor,
|
|
8
|
+
isToolcraftRuntimeBackgroundEnabled,
|
|
9
|
+
} from "../state/canvas-background-state";
|
|
10
|
+
import type { ToolcraftState } from "../state/types";
|
|
11
|
+
import {
|
|
12
|
+
downloadToolcraftArtifact,
|
|
13
|
+
type ToolcraftArtifactDownloadRequest,
|
|
14
|
+
type ToolcraftArtifactDownloadResult,
|
|
15
|
+
} from "./artifact-download";
|
|
16
|
+
import {
|
|
17
|
+
createToolcraftArtifactFrameState,
|
|
18
|
+
getToolcraftArtifactTimelineProgress,
|
|
19
|
+
} from "./artifact-frame-state";
|
|
20
|
+
import { resolveToolcraftStillArtifactFrame } from "./artifact-scene-frame";
|
|
21
|
+
import {
|
|
22
|
+
ToolcraftSceneExportError,
|
|
23
|
+
validateToolcraftArtifactSize,
|
|
24
|
+
} from "./export-frame";
|
|
25
|
+
import { normalizeToolcraftExportError } from "./export-error";
|
|
26
|
+
import type { ToolcraftProductSvgExportRenderer } from "./product-svg-export-renderer";
|
|
27
|
+
import {
|
|
28
|
+
createToolcraftSvgDocument,
|
|
29
|
+
createToolcraftSvgProductContainer,
|
|
30
|
+
serializeToolcraftSvgDocument,
|
|
31
|
+
} from "./svg-document";
|
|
32
|
+
|
|
33
|
+
export type ToolcraftSvgArtifactExportResult = Readonly<{
|
|
34
|
+
byteLength: number;
|
|
35
|
+
extension: ".svg";
|
|
36
|
+
height: number;
|
|
37
|
+
mediaType: "image/svg+xml";
|
|
38
|
+
vectorElementCount: number;
|
|
39
|
+
width: number;
|
|
40
|
+
}>;
|
|
41
|
+
|
|
42
|
+
export type ToolcraftSvgArtifactExportRequest = Readonly<{
|
|
43
|
+
boundsProvider: ToolcraftProductSceneBoundsProvider | undefined;
|
|
44
|
+
downloadArtifact?: (
|
|
45
|
+
request: ToolcraftArtifactDownloadRequest,
|
|
46
|
+
) => ToolcraftArtifactDownloadResult;
|
|
47
|
+
productSceneRequired: boolean;
|
|
48
|
+
rendererPipeline: ToolcraftRendererPipelineClient | null;
|
|
49
|
+
reportProgress: (progress: number) => void;
|
|
50
|
+
state: ToolcraftState;
|
|
51
|
+
svgExportRenderer: ToolcraftProductSvgExportRenderer;
|
|
52
|
+
visibility: ToolcraftRuntimeSceneVisibility;
|
|
53
|
+
}>;
|
|
54
|
+
|
|
55
|
+
export async function exportToolcraftSvgArtifact(
|
|
56
|
+
request: ToolcraftSvgArtifactExportRequest,
|
|
57
|
+
): Promise<ToolcraftSvgArtifactExportResult> {
|
|
58
|
+
const frameState = createToolcraftArtifactFrameState(
|
|
59
|
+
request.state,
|
|
60
|
+
request.state.timeline.currentTimeSeconds,
|
|
61
|
+
);
|
|
62
|
+
const frame = resolveToolcraftStillArtifactFrame({
|
|
63
|
+
boundsProvider: request.boundsProvider,
|
|
64
|
+
productSceneRequired: request.productSceneRequired,
|
|
65
|
+
state: frameState,
|
|
66
|
+
visibility: request.visibility,
|
|
67
|
+
});
|
|
68
|
+
const sizeValidation = validateToolcraftArtifactSize(frame);
|
|
69
|
+
if (!sizeValidation.ok) {
|
|
70
|
+
throw new ToolcraftSceneExportError(sizeValidation);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { document: svgDocument } = createToolcraftSvgDocument(frame);
|
|
74
|
+
const { container } = createToolcraftSvgProductContainer();
|
|
75
|
+
request.reportProgress(0.1);
|
|
76
|
+
try {
|
|
77
|
+
await request.svgExportRenderer.renderFrame({
|
|
78
|
+
container,
|
|
79
|
+
frame,
|
|
80
|
+
rendererPipeline: request.rendererPipeline,
|
|
81
|
+
state: frameState,
|
|
82
|
+
timeSeconds: frameState.timeline.currentTimeSeconds,
|
|
83
|
+
timelineProgress: getToolcraftArtifactTimelineProgress(frameState),
|
|
84
|
+
});
|
|
85
|
+
} catch (error) {
|
|
86
|
+
throw normalizeToolcraftExportError(error, {
|
|
87
|
+
code: "svg-render-failed",
|
|
88
|
+
message: "Toolcraft could not render product vectors for SVG export.",
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
request.reportProgress(0.65);
|
|
92
|
+
|
|
93
|
+
const serialized = serializeToolcraftSvgDocument({
|
|
94
|
+
backgroundColor: isToolcraftRuntimeBackgroundEnabled(frameState)
|
|
95
|
+
? (getToolcraftRuntimeBackgroundColor(frameState) ?? "#000000")
|
|
96
|
+
: null,
|
|
97
|
+
container,
|
|
98
|
+
document: svgDocument,
|
|
99
|
+
frame,
|
|
100
|
+
});
|
|
101
|
+
const blob = new Blob([serialized.source], {
|
|
102
|
+
type: "image/svg+xml;charset=utf-8",
|
|
103
|
+
});
|
|
104
|
+
request.reportProgress(0.9);
|
|
105
|
+
(request.downloadArtifact ?? downloadToolcraftArtifact)({
|
|
106
|
+
blob,
|
|
107
|
+
extension: ".svg",
|
|
108
|
+
rawBaseFileName: request.svgExportRenderer.baseFileName,
|
|
109
|
+
});
|
|
110
|
+
request.reportProgress(1);
|
|
111
|
+
|
|
112
|
+
return Object.freeze({
|
|
113
|
+
byteLength: blob.size,
|
|
114
|
+
extension: ".svg",
|
|
115
|
+
height: frame.height,
|
|
116
|
+
mediaType: "image/svg+xml",
|
|
117
|
+
vectorElementCount: serialized.vectorElementCount,
|
|
118
|
+
width: frame.width,
|
|
119
|
+
});
|
|
120
|
+
}
|