@pixel-point/toolcraft 0.0.14 → 0.0.15
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/README.md +13 -2
- package/package.json +1 -1
- package/scripts/prepare-pack.mjs +2 -28
- package/src/cli-io.mjs +174 -0
- package/src/cli-package-manager-flow.test.mjs +206 -0
- package/src/cli.mjs +7 -495
- package/src/cli.test.mjs +34 -177
- package/src/create-command.mjs +152 -0
- package/src/create-options.mjs +194 -0
- package/src/generate-test-assertions.mjs +27 -0
- package/src/generate-test-doc-assertions.mjs +162 -0
- package/src/generate-test-file-assertions.mjs +251 -0
- package/src/generate-test-fs-utils.mjs +59 -0
- package/src/generate-test-integrity-assertions.mjs +30 -0
- package/src/generate-test-integrity-framework-assertions.mjs +222 -0
- package/src/generate-test-integrity-manifest-assertions.mjs +150 -0
- package/src/generate-test-integrity-ownership-assertions.mjs +127 -0
- package/src/generate-test-integrity-test-utils.mjs +102 -0
- package/src/generate-test-package-assertions.mjs +75 -0
- package/src/generate-test-product-fixture.mjs +84 -0
- package/src/generate-test-product-fixture.test.mjs +73 -0
- package/src/generate-test-standalone-assertions.mjs +209 -0
- package/src/generate-transactional.test.mjs +151 -0
- package/src/generate.mjs +182 -102
- package/src/generate.test.mjs +242 -338
- package/src/generated-integrity-manifest.mjs +127 -0
- package/src/generated-integrity-manifest.test.mjs +151 -0
- package/src/generated-source-policy.mjs +22 -0
- package/src/generated-source-policy.test.mjs +35 -0
- package/src/generated-target-policy.mjs +55 -0
- package/src/generation-transaction.mjs +135 -0
- package/src/generation-transaction.test.mjs +74 -0
- package/src/package-json.mjs +18 -1
- package/src/package-json.test.mjs +38 -5
- package/src/package-manager.mjs +2 -0
- package/src/package-manager.test.mjs +5 -1
- package/src/packaged-template-fallback.test.mjs +126 -0
- package/src/prepare-pack-templates.mjs +34 -0
- package/templates/runtime/contracts/component-contract-builders.ts +95 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +293 -0
- package/templates/runtime/contracts/component-contracts.choices.ts +322 -0
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +210 -0
- package/templates/runtime/contracts/component-contracts.inputs.ts +252 -0
- package/templates/runtime/contracts/component-contracts.media-custom.test.ts +116 -0
- package/templates/runtime/contracts/component-contracts.media-custom.ts +144 -0
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +229 -0
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +76 -0
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +135 -0
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +148 -0
- package/templates/runtime/contracts/component-contracts.runtime.ts +361 -0
- package/templates/runtime/contracts/component-contracts.test.ts +39 -1458
- package/templates/runtime/contracts/component-contracts.ts +44 -1505
- package/templates/runtime/contracts/component-contracts.visual.test.ts +316 -0
- package/templates/runtime/contracts/component-contracts.visual.ts +385 -0
- package/templates/runtime/contracts/contract-manifest.test.ts +64 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +29 -4
- package/templates/runtime/contracts/decision-contracts.ts +38 -1
- package/templates/runtime/index.ts +1 -0
- package/templates/runtime/react/{runtime-public-api.test.tsx → app-shell/runtime-public-api.test.tsx} +29 -7
- package/templates/runtime/react/{settings-transfer.test.ts → app-shell/settings-transfer.test.ts} +4 -4
- package/templates/runtime/react/{settings-transfer.ts → app-shell/settings-transfer.ts} +3 -3
- package/templates/runtime/react/{toolbar-panel.test.tsx → app-shell/toolbar-panel.test.tsx} +2 -2
- package/templates/runtime/react/{toolbar-panel.tsx → app-shell/toolbar-panel.tsx} +3 -3
- package/templates/runtime/react/{toolcraft-app.integration.test.tsx → app-shell/toolcraft-app.integration.test.tsx} +6 -6
- package/templates/runtime/react/{toolcraft-app.test.tsx → app-shell/toolcraft-app.test.tsx} +3 -3
- package/templates/runtime/react/{toolcraft-app.tsx → app-shell/toolcraft-app.tsx} +11 -8
- package/templates/runtime/react/{toolcraft-root.test.tsx → app-shell/toolcraft-root.test.tsx} +1 -1
- package/templates/runtime/react/{toolcraft-root.tsx → app-shell/toolcraft-root.tsx} +5 -5
- package/templates/runtime/react/{use-toolcraft.ts → app-shell/use-toolcraft.ts} +1 -1
- package/templates/runtime/react/canvas/canvas-default-media-layer.tsx +81 -0
- package/templates/runtime/react/canvas/canvas-media-transform.ts +33 -0
- package/templates/runtime/react/canvas/canvas-shell-interactions.test.tsx +156 -0
- package/templates/runtime/react/canvas/canvas-shell-media-rendering.test.tsx +87 -0
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +102 -0
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +108 -0
- package/templates/runtime/react/canvas/canvas-shell-upload.test.tsx +106 -0
- package/templates/runtime/react/canvas/canvas-shell.tsx +146 -0
- package/templates/runtime/react/canvas/canvas-upload-routing.ts +84 -0
- package/templates/runtime/react/{media-file.ts → canvas/media-file.ts} +1 -1
- package/templates/runtime/react/canvas/use-canvas-drop-import.ts +145 -0
- package/templates/runtime/react/canvas/use-canvas-viewport-interactions.ts +227 -0
- package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +89 -0
- package/templates/runtime/react/{controls-panel-filedrop-reorder.test.tsx → controls-panel/__tests__/controls-panel-filedrop-reorder.test.tsx} +4 -4
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.actions-layout.test.tsx +91 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +213 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-layout.test.tsx +366 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.color-picker-models.test.tsx +169 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.compound-layout.test.tsx +160 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +352 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.curves.test.tsx +226 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.floating-shell.test.tsx +13 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.font-picker.test.tsx +302 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +401 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.gradient-control.test.tsx +139 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.help-policy.test.tsx +103 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.image-picker.test.tsx +16 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.inline-layout.test.tsx +290 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.keyframes.test.tsx +175 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-files.test.tsx +121 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-image.test.tsx +363 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.media-upload-multi-image.test.tsx +105 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.range-slider-editing.test.tsx +149 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.section-shell.test.tsx +138 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.select-layout.test.tsx +148 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.setup-controls.test.tsx +189 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.slider-rendering.test.tsx +317 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.state-reset.test.tsx +137 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.structure.test.tsx +66 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.text-input.test.tsx +205 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-interaction.test.tsx +388 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.vector-layout.test.tsx +155 -0
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +172 -0
- package/templates/runtime/react/{control-conditions.ts → controls-panel/conditions/control-conditions.ts} +26 -3
- package/templates/runtime/react/{control-renderers.ts → controls-panel/control-renderers.ts} +2 -2
- package/templates/runtime/react/controls-panel/controls-panel.tsx +250 -0
- package/templates/runtime/react/controls-panel/keyframes/controls-panel-keyframes.tsx +265 -0
- package/templates/runtime/react/controls-panel/layout/controls-panel-collapse-storage.ts +131 -0
- package/templates/runtime/react/controls-panel/layout/controls-panel-help.tsx +132 -0
- package/templates/runtime/react/controls-panel/layout/controls-panel-inline-layout.tsx +311 -0
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +216 -0
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +401 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-action-renderer.tsx +137 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-basic-renderers.tsx +421 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +286 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-compound-renderers.tsx +366 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +173 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +23 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +55 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-settings-transfer-renderer.tsx +45 -0
- package/templates/runtime/react/controls-panel/testing/controls-panel-test-utils.tsx +300 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-aspect-ratio-values.ts +94 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +87 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-color-values.ts +82 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-font-values.ts +69 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-spatial-values.ts +64 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +93 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-value-primitives.ts +30 -0
- package/templates/runtime/react/controls-panel/values/controls-panel-values.ts +7 -0
- package/templates/runtime/react/index.ts +13 -13
- package/templates/runtime/react/{layer-tree.ts → layers/layer-tree.ts} +1 -1
- package/templates/runtime/react/layers/layers-panel-drag-drop.test.tsx +190 -0
- package/templates/runtime/react/layers/layers-panel-editing.test.tsx +41 -0
- package/templates/runtime/react/layers/layers-panel-insert-targets.test.ts +87 -0
- package/templates/runtime/react/layers/layers-panel-insert-targets.ts +254 -0
- package/templates/runtime/react/layers/layers-panel-model.ts +15 -0
- package/templates/runtime/react/layers/layers-panel-rendering.test.tsx +43 -0
- package/templates/runtime/react/layers/layers-panel-reorder.ts +148 -0
- package/templates/runtime/react/layers/layers-panel-row.tsx +475 -0
- package/templates/runtime/react/layers/layers-panel-test-utils.tsx +135 -0
- package/templates/runtime/react/layers/layers-panel-visibility.test.tsx +126 -0
- package/templates/runtime/react/layers/layers-panel.tsx +349 -0
- package/templates/runtime/react/layers/use-layers-panel-drag-controller.ts +327 -0
- package/templates/runtime/react/{panel-host-types.ts → panel-host/panel-host-types.ts} +2 -2
- package/templates/runtime/react/{panel-host.test.tsx → panel-host/panel-host.test.tsx} +3 -3
- package/templates/runtime/react/{panel-host.tsx → panel-host/panel-host.tsx} +1 -1
- package/templates/runtime/react/timeline/timeline-easing-editor.tsx +409 -0
- package/templates/runtime/react/timeline/timeline-easing-geometry.ts +42 -0
- package/templates/runtime/react/timeline/timeline-easing-icons.tsx +135 -0
- package/templates/runtime/react/timeline/timeline-easing-model.test.ts +87 -0
- package/templates/runtime/react/timeline/timeline-easing-model.ts +271 -0
- package/templates/runtime/react/timeline/timeline-easing-popover-content.tsx +227 -0
- package/templates/runtime/react/timeline/timeline-easing-popover-layout.ts +69 -0
- package/templates/runtime/react/timeline/timeline-easing-popover.tsx +60 -0
- package/templates/runtime/react/timeline/timeline-event-targets.ts +19 -0
- package/templates/runtime/react/timeline/timeline-expanded-content.tsx +299 -0
- package/templates/runtime/react/timeline/timeline-icon-button.tsx +51 -0
- package/templates/runtime/react/timeline/timeline-keyframe-row.tsx +360 -0
- package/templates/runtime/react/timeline/timeline-keyframes.ts +23 -0
- package/templates/runtime/react/timeline/timeline-panel-floating-layout.test.tsx +328 -0
- package/templates/runtime/react/timeline/timeline-panel-header.tsx +404 -0
- package/templates/runtime/react/timeline/timeline-panel-keyframes.test.tsx +90 -0
- package/templates/runtime/react/timeline/timeline-panel-layout.ts +30 -0
- package/templates/runtime/react/timeline/timeline-panel-responsive-layout.ts +182 -0
- package/templates/runtime/react/timeline/timeline-panel-test-utils.tsx +88 -0
- package/templates/runtime/react/timeline/timeline-panel-transport.test.tsx +202 -0
- package/templates/runtime/react/timeline/timeline-panel-upload.test.tsx +53 -0
- package/templates/runtime/react/timeline/timeline-panel.tsx +449 -0
- package/templates/runtime/react/timeline/timeline-playback-hooks.ts +254 -0
- package/templates/runtime/schema/assembly-contract.ts +271 -0
- package/templates/runtime/schema/control-schema-normalization.ts +55 -0
- package/templates/runtime/schema/controls-panel-actions.ts +141 -0
- package/templates/runtime/schema/controls-panel-layout-groups.ts +144 -0
- package/templates/runtime/schema/controls-panel-normalization.ts +19 -0
- package/templates/runtime/schema/controls-panel-section-layout.ts +140 -0
- package/templates/runtime/schema/controls-panel-section-titles.ts +161 -0
- package/templates/runtime/schema/define-toolcraft-test-utils.ts +18 -0
- package/templates/runtime/schema/define-toolcraft.actions.test.ts +182 -0
- package/templates/runtime/schema/define-toolcraft.assembly.test.ts +246 -0
- package/templates/runtime/schema/define-toolcraft.canvas.test.ts +150 -0
- package/templates/runtime/schema/define-toolcraft.control-layout.test.ts +345 -0
- package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +304 -0
- package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +69 -0
- package/templates/runtime/schema/define-toolcraft.setup-persistence.test.ts +66 -0
- package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +116 -0
- package/templates/runtime/schema/define-toolcraft.setup-settings-transfer.test.ts +291 -0
- package/templates/runtime/schema/define-toolcraft.ts +24 -1449
- package/templates/runtime/schema/panels-schema-normalization.ts +49 -0
- package/templates/runtime/schema/runtime-section-titles.ts +1 -0
- package/templates/runtime/schema/runtime-setup-section.ts +282 -0
- package/templates/runtime/schema/schema-resolvers.ts +168 -0
- package/templates/runtime/schema/types.ts +17 -0
- package/templates/runtime/state/canvas-reducer.ts +106 -0
- package/templates/runtime/state/canvas-state.ts +209 -0
- package/templates/runtime/state/controls-reducer.ts +277 -0
- package/templates/runtime/state/history-patches.ts +174 -0
- package/templates/runtime/state/layer-state.ts +12 -0
- package/templates/runtime/state/layers-reducer.ts +318 -0
- package/templates/runtime/state/media-reducer.ts +283 -0
- package/templates/runtime/state/media-state.ts +105 -0
- package/templates/runtime/state/panels-reducer.ts +58 -0
- package/templates/runtime/state/persistence-merge.ts +53 -0
- package/templates/runtime/state/persistence-reader-canvas.ts +27 -0
- package/templates/runtime/state/persistence-reader-layers.ts +73 -0
- package/templates/runtime/state/persistence-reader-media.ts +82 -0
- package/templates/runtime/state/persistence-reader-panels.ts +56 -0
- package/templates/runtime/state/persistence-reader-primitives.ts +27 -0
- package/templates/runtime/state/persistence-reader-timeline.ts +145 -0
- package/templates/runtime/state/persistence-reader-values.ts +40 -0
- package/templates/runtime/state/persistence-readers.ts +72 -0
- package/templates/runtime/state/persistence-shared.ts +23 -0
- package/templates/runtime/state/persistence-snapshot.ts +57 -0
- package/templates/runtime/state/persistence.ts +16 -581
- package/templates/runtime/state/reducer-canvas-panels.test.ts +324 -0
- package/templates/runtime/state/reducer-controls.test.ts +158 -0
- package/templates/runtime/state/reducer-layers.test.ts +306 -0
- package/templates/runtime/state/reducer-media-import-sizing.test.ts +197 -0
- package/templates/runtime/state/reducer-media-reorder-history.test.ts +116 -0
- package/templates/runtime/state/reducer-media-reset.test.ts +249 -0
- package/templates/runtime/state/reducer-media-test-utils.ts +40 -0
- package/templates/runtime/state/reducer-media-transform.test.ts +52 -0
- package/templates/runtime/state/reducer-test-utils.ts +30 -0
- package/templates/runtime/state/reducer-timeline.test.ts +242 -0
- package/templates/runtime/state/reducer.ts +57 -1785
- package/templates/runtime/state/timeline-reducer.ts +412 -0
- package/templates/runtime/state/timeline-values.test.ts +45 -0
- package/templates/runtime/state/timeline-values.ts +45 -0
- package/templates/runtime/testing/performance-browser-policy.test.ts +81 -0
- package/templates/runtime/testing/performance-browser-policy.ts +102 -0
- package/templates/runtime/testing/performance-budget-validation.ts +84 -0
- package/templates/runtime/testing/performance-control-classification.test.ts +106 -0
- package/templates/runtime/testing/performance-control-classification.ts +101 -0
- package/templates/runtime/testing/performance-coverage-context.ts +44 -0
- package/templates/runtime/testing/performance-coverage-renderer-policy.ts +221 -0
- package/templates/runtime/testing/performance-coverage-scenario-policy.ts +147 -0
- package/templates/runtime/testing/performance-coverage-target-policy.ts +121 -0
- package/templates/runtime/testing/performance-coverage-validator.ts +34 -0
- package/templates/runtime/testing/performance-export-coverage.test.ts +234 -0
- package/templates/runtime/testing/performance-fixture-load-profile.test.ts +360 -0
- package/templates/runtime/testing/performance-fixture-media.test.ts +80 -0
- package/templates/runtime/testing/performance-fixture-stress.test.ts +314 -0
- package/templates/runtime/testing/performance-fixture-validation.ts +255 -0
- package/templates/runtime/testing/performance-fixture-values.ts +275 -0
- package/templates/runtime/testing/performance-fixture-workload.test.ts +140 -0
- package/templates/runtime/testing/performance-load-profile-validation.ts +467 -0
- package/templates/runtime/testing/performance-renderer-coverage.test.ts +325 -0
- package/templates/runtime/testing/performance-renderer-pipeline-coverage.test.ts +115 -0
- package/templates/runtime/testing/performance-renderer-pipeline-interactions.test.ts +201 -0
- package/templates/runtime/testing/performance-renderer-pipeline-passes.test.ts +247 -0
- package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +360 -0
- package/templates/runtime/testing/performance-renderer-technique-validation.ts +329 -0
- package/templates/runtime/testing/performance-renderer-technique.test.ts +275 -0
- package/templates/runtime/testing/performance-renderer-validation.ts +2 -0
- package/templates/runtime/testing/performance-scenario-coverage.test.ts +303 -0
- package/templates/runtime/testing/performance-scenario-validation.ts +49 -0
- package/templates/runtime/testing/performance-schema-derived-workloads.test.ts +231 -0
- package/templates/runtime/testing/performance-schema-queries.ts +181 -0
- package/templates/runtime/testing/performance-test-fixtures/index.ts +4 -0
- package/templates/runtime/testing/performance-test-fixtures/renderer-pipelines.ts +322 -0
- package/templates/runtime/testing/performance-test-fixtures/scenarios.ts +172 -0
- package/templates/runtime/testing/performance-test-fixtures/schemas.ts +151 -0
- package/templates/runtime/testing/performance-test-fixtures/stress-fixtures.ts +133 -0
- package/templates/runtime/testing/performance-test-fixtures.ts +1 -0
- package/templates/runtime/testing/performance-types.ts +338 -0
- package/templates/runtime/testing/performance.ts +15 -2485
- package/templates/starter/AGENTS.md +41 -26
- package/templates/starter/LICENSE.md +18 -95
- package/templates/starter/NOTICE.md +3 -3
- package/templates/starter/docs/toolcraft/README.md +5 -5
- package/templates/starter/docs/toolcraft/acceptance-testing.md +36 -8
- package/templates/starter/docs/toolcraft/assembly-workflow.md +12 -15
- package/templates/starter/docs/toolcraft/component-rules.md +6 -2
- package/templates/starter/docs/toolcraft/core/layout.md +1 -0
- package/templates/starter/docs/toolcraft/core/performance.md +7 -4
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +11 -4
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +1 -0
- package/templates/starter/docs/toolcraft/custom-controls.md +8 -1
- package/templates/starter/docs/toolcraft/decision-contract.md +26 -22
- package/templates/starter/docs/toolcraft/performance.md +42 -16
- package/templates/starter/docs/toolcraft/schema-reference.md +34 -23
- package/templates/starter/docs/toolcraft/workflow.md +25 -17
- package/templates/starter/e2e/app-browser-acceptance-evidence.spec.ts +111 -0
- package/templates/starter/e2e/app-browser-control-coverage.spec.ts +118 -0
- package/templates/starter/e2e/app-browser-performance-evidence.spec.ts +217 -0
- package/templates/starter/e2e/app-browser-performance-probe.spec.ts +322 -0
- package/templates/starter/e2e/app-browser-proof-session.spec.ts +196 -0
- package/templates/starter/e2e/app-browser-runtime-evidence.spec.ts +9 -0
- package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +240 -0
- package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +180 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +310 -0
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +432 -0
- package/templates/starter/e2e/app-browser-shell.spec.ts +171 -0
- package/templates/starter/e2e/app-browser-timeline-layers-reference.spec.ts +70 -0
- package/templates/starter/e2e/app-performance.spec.ts +0 -491
- package/templates/starter/e2e/browser-acceptance-outcome-helpers.ts +97 -0
- package/templates/starter/e2e/browser-acceptance-transition-helpers.ts +74 -0
- package/templates/starter/e2e/browser-conditional-output-evidence-helpers.ts +230 -0
- package/templates/starter/e2e/browser-control-target-helpers.ts +109 -0
- package/templates/starter/e2e/browser-layer-evidence-helpers.ts +229 -0
- package/templates/starter/e2e/browser-proof-session.ts +392 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +136 -0
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +290 -0
- package/templates/starter/e2e/browser-runtime-evidence.ts +27 -0
- package/templates/starter/e2e/browser-state-evidence-helpers.ts +205 -0
- package/templates/starter/e2e/browser-timeline-evidence-helpers.ts +319 -0
- package/templates/starter/e2e/canvas-handle-helpers.ts +86 -4
- package/templates/starter/e2e/export-artifact-helpers.ts +132 -0
- package/templates/starter/e2e/performance-budget-helpers.ts +159 -0
- package/templates/starter/e2e/performance-canvas-helpers.ts +123 -0
- package/templates/starter/e2e/performance-control-helpers.ts +3 -0
- package/templates/starter/e2e/performance-control-layout-helpers.ts +161 -0
- package/templates/starter/e2e/performance-fixture-helpers.ts +217 -0
- package/templates/starter/e2e/performance-frame-probe.ts +247 -0
- package/templates/starter/e2e/performance-helpers.ts +6 -854
- package/templates/starter/e2e/performance-interaction-measurement.ts +251 -0
- package/templates/starter/e2e/performance-measurement-evidence.ts +72 -0
- package/templates/starter/e2e/performance-output-action-helpers.spec.ts +43 -0
- package/templates/starter/e2e/performance-output-action-helpers.ts +109 -0
- package/templates/starter/e2e/performance-probe-helpers.ts +12 -0
- package/templates/starter/e2e/performance-render-scale-helpers.ts +55 -0
- package/templates/starter/e2e/performance-slider-helpers.ts +271 -0
- package/templates/starter/e2e/product-observable-helpers.ts +72 -17
- package/templates/starter/e2e/stable-outcome-helpers.ts +208 -0
- package/templates/starter/package.json +10 -5
- package/templates/starter/playwright.config.ts +5 -2
- package/templates/starter/scripts/check-ai-skills.mjs +14 -8
- package/templates/starter/scripts/check-ai-skills.test.mjs +64 -0
- package/templates/starter/scripts/check-toolcraft-code-health.mjs +108 -0
- package/templates/starter/scripts/check-toolcraft-code-health.test.mjs +213 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +47 -34
- package/templates/starter/scripts/check-toolcraft-integrity.mjs +141 -144
- package/templates/starter/scripts/run-browser-performance.mjs +118 -0
- package/templates/starter/scripts/run-browser-performance.test.mjs +53 -0
- package/templates/starter/scripts/toolcraft-code-health-core.mjs +297 -0
- package/templates/starter/scripts/toolcraft-contract-doc-integrity.mjs +77 -0
- package/templates/starter/scripts/toolcraft-contract-doc-integrity.test.mjs +81 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +113 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.mjs +128 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.test.mjs +72 -0
- package/templates/starter/scripts/toolcraft-integrity-manifest.mjs +172 -0
- package/templates/starter/scripts/toolcraft-integrity-policy.mjs +60 -0
- package/templates/starter/scripts/toolcraft-product-boundary-ast-utils.mjs +23 -0
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +264 -0
- package/templates/starter/scripts/toolcraft-product-boundary-test-fixtures.mjs +16 -0
- package/templates/starter/scripts/toolcraft-product-boundary.mjs +243 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +289 -0
- package/templates/starter/scripts/toolcraft-product-dependency-graph.mjs +176 -0
- package/templates/starter/scripts/toolcraft-product-dependency-graph.test.mjs +196 -0
- package/templates/starter/scripts/toolcraft-product-dependency-resolution.mjs +279 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary-ast.mjs +91 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +138 -0
- package/templates/starter/scripts/toolcraft-product-style-boundary.mjs +219 -0
- package/templates/starter/scripts/toolcraft-source-inventory.d.mts +46 -0
- package/templates/starter/scripts/toolcraft-source-inventory.mjs +187 -0
- package/templates/starter/scripts/toolcraft-source-inventory.test.mjs +132 -0
- package/templates/starter/scripts/toolcraft-source-ownership.mjs +167 -0
- package/templates/starter/scripts/toolcraft-source-ownership.test.mjs +113 -0
- package/templates/starter/scripts/toolcraft-static-string.mjs +104 -0
- package/templates/starter/scripts/toolcraft-verification-inventory.mjs +123 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.d.mts +19 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.mjs +284 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +282 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.d.mts +32 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.mjs +88 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-contract.test.mjs +87 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.mjs +109 -0
- package/templates/starter/scripts/toolcraft-vitest-runtime-evidence-reporter.test.mjs +111 -0
- package/templates/starter/scripts/toolcraft-workflow-routes.mjs +314 -0
- package/templates/starter/scripts/toolcraft-workflow-routes.test.mjs +204 -0
- package/templates/starter/src/app/acceptance/actions.ts +30 -0
- package/templates/starter/src/app/acceptance/animation-intent.ts +184 -0
- package/templates/starter/src/app/acceptance/canvas-handle-acceptance.ts +70 -0
- package/templates/starter/src/app/acceptance/color-bank-labels.ts +164 -0
- package/templates/starter/src/app/acceptance/conditions.ts +80 -0
- package/templates/starter/src/app/acceptance/control-acceptance-context.ts +70 -0
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +271 -0
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +149 -0
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +189 -0
- package/templates/starter/src/app/acceptance/control-acceptance.ts +70 -0
- package/templates/starter/src/app/acceptance/control-component-rules.ts +277 -0
- package/templates/starter/src/app/acceptance/control-labels.ts +223 -0
- package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +107 -0
- package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +104 -0
- package/templates/starter/src/app/acceptance/control-layout-model.ts +159 -0
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +164 -0
- package/templates/starter/src/app/acceptance/control-layout.ts +45 -0
- package/templates/starter/src/app/acceptance/control-order.ts +123 -0
- package/templates/starter/src/app/acceptance/control-parts.ts +47 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.ts +183 -0
- package/templates/starter/src/app/acceptance/controls.ts +27 -0
- package/templates/starter/src/app/acceptance/coverage.ts +81 -0
- package/templates/starter/src/app/acceptance/custom-controls.ts +140 -0
- package/templates/starter/src/app/acceptance/inline-layout.ts +192 -0
- package/templates/starter/src/app/acceptance/media-upload.ts +55 -0
- package/templates/starter/src/app/acceptance/output-background-rules.ts +135 -0
- package/templates/starter/src/app/acceptance/output-export-actions.test.ts +76 -0
- package/templates/starter/src/app/acceptance/output-export-actions.ts +34 -0
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +46 -0
- package/templates/starter/src/app/acceptance/output-export-model.ts +146 -0
- package/templates/starter/src/app/acceptance/output-export.ts +45 -0
- package/templates/starter/src/app/acceptance/output-image-export-rules.ts +87 -0
- package/templates/starter/src/app/acceptance/reference-runtime-coverage.ts +96 -0
- package/templates/starter/src/app/acceptance/reference-runtime-feature-inventory.ts +171 -0
- package/templates/starter/src/app/acceptance/reference-runtime-study.ts +73 -0
- package/templates/starter/src/app/acceptance/reference-runtime-timeline.ts +291 -0
- package/templates/starter/src/app/acceptance/reference-runtime.ts +99 -0
- package/templates/starter/src/app/acceptance/runtime-coverage.ts +290 -0
- package/templates/starter/src/app/acceptance/runtime-setup.ts +117 -0
- package/templates/starter/src/app/acceptance/section-title-rules.ts +8 -0
- package/templates/starter/src/app/acceptance/sections.ts +6 -0
- package/templates/starter/src/app/acceptance/semantic.ts +63 -0
- package/templates/starter/src/app/acceptance/timeline-loop.ts +21 -0
- package/templates/starter/src/app/acceptance/types.ts +363 -0
- package/templates/starter/src/app/acceptance/validate-coverage.ts +217 -0
- package/templates/starter/src/app/acceptance/validation-pipeline.test.ts +56 -0
- package/templates/starter/src/app/acceptance/validation-pipeline.ts +60 -0
- package/templates/starter/src/app/acceptance/video-reference-study.ts +217 -0
- package/templates/starter/src/app/starter-acceptance-data.ts +21 -0
- package/templates/starter/src/app/starter-acceptance.animation-intent.test.ts +383 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +349 -0
- package/templates/starter/src/app/starter-acceptance.base-coverage.test.ts +47 -0
- package/templates/starter/src/app/starter-acceptance.canvas-handles.test.ts +71 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +199 -0
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +244 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +63 -0
- package/templates/starter/src/app/starter-acceptance.control-label-context.test.ts +172 -0
- package/templates/starter/src/app/starter-acceptance.control-labels.test.ts +387 -0
- package/templates/starter/src/app/starter-acceptance.control-naming-rules.test.ts +215 -0
- package/templates/starter/src/app/starter-acceptance.control-order.test.ts +274 -0
- package/templates/starter/src/app/starter-acceptance.control-state.test.ts +275 -0
- package/templates/starter/src/app/starter-acceptance.curves-rules.test.ts +184 -0
- package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +200 -0
- package/templates/starter/src/app/starter-acceptance.custom-control-coverage.test.ts +111 -0
- package/templates/starter/src/app/starter-acceptance.custom-control-fit-check.test.ts +135 -0
- package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +74 -0
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +107 -0
- package/templates/starter/src/app/starter-acceptance.framework-boundary.test.ts +327 -0
- package/templates/starter/src/app/starter-acceptance.image-video-export-settings.test.ts +328 -0
- package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +242 -0
- package/templates/starter/src/app/starter-acceptance.layers.test.ts +203 -0
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +110 -0
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +153 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +97 -0
- package/templates/starter/src/app/starter-acceptance.persistence-coverage.test.ts +134 -0
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +202 -0
- package/templates/starter/src/app/starter-acceptance.product-readiness-rules.test.ts +14 -0
- package/templates/starter/src/app/starter-acceptance.product-readiness-test-utils.ts +25 -0
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +50 -0
- package/templates/starter/src/app/starter-acceptance.product-worklog.test.ts +27 -0
- package/templates/starter/src/app/starter-acceptance.range-slider-rules.test.ts +147 -0
- package/templates/starter/src/app/starter-acceptance.reference-custom-timeline.test.ts +197 -0
- package/templates/starter/src/app/starter-acceptance.reference-foundation.test.ts +304 -0
- package/templates/starter/src/app/starter-acceptance.reference-test-utils.ts +102 -0
- package/templates/starter/src/app/starter-acceptance.reference-timeline.test.ts +267 -0
- package/templates/starter/src/app/starter-acceptance.schema-test-utils.ts +116 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +373 -0
- package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +260 -0
- package/templates/starter/src/app/starter-acceptance.section-titles.test.ts +180 -0
- package/templates/starter/src/app/starter-acceptance.setup-readiness.test.ts +205 -0
- package/templates/starter/src/app/starter-acceptance.slider-rules.test.ts +470 -0
- package/templates/starter/src/app/starter-acceptance.slider-unit-rules.test.ts +61 -0
- package/templates/starter/src/app/starter-acceptance.source-test-utils.ts +43 -0
- package/templates/starter/src/app/starter-acceptance.test-utils.ts +21 -0
- package/templates/starter/src/app/starter-acceptance.text-control-kind.test.ts +89 -0
- package/templates/starter/src/app/starter-acceptance.timeline-playback.test.ts +264 -0
- package/templates/starter/src/app/starter-acceptance.timeline-test-utils.ts +56 -0
- package/templates/starter/src/app/starter-acceptance.toggle-pair-layout.test.ts +200 -0
- package/templates/starter/src/app/starter-acceptance.toggle-parameter-layout.test.ts +277 -0
- package/templates/starter/src/app/starter-acceptance.ts +151 -4576
- package/templates/starter/src/app/starter-acceptance.video-export-test-utils.ts +37 -0
- package/templates/starter/src/app/starter-acceptance.video-reference-study.test.ts +262 -0
- package/templates/starter/src/app/starter-acceptance.worklog-test-utils.ts +428 -0
- package/templates/starter/src/app/starter-acceptance.worklog.test.ts +283 -0
- package/templates/starter/src/app/starter-automated-runtime-evidence.test.ts +34 -0
- package/templates/starter/src/app/starter-composition.tsx +7 -0
- package/templates/starter/src/app/starter-performance-test-utils.ts +275 -0
- package/templates/starter/src/app/starter-performance.budgets.test.ts +374 -0
- package/templates/starter/src/app/starter-performance.gates.test.ts +128 -0
- package/templates/starter/src/app/starter-performance.renderer-source.test.ts +136 -0
- package/templates/starter/src/app/starter-performance.renderer-technique.test.ts +291 -0
- package/templates/starter/src/app/starter-performance.scenarios.test.ts +355 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.test.ts +253 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +243 -0
- package/templates/starter/src/routes/index.tsx +11 -2
- package/templates/starter/vite.config.ts +8 -0
- package/templates/ui/components/controls/color/color-control-types.ts +38 -0
- package/templates/ui/components/controls/color/color-control.tsx +19 -437
- package/templates/ui/components/controls/color/color-footer.tsx +272 -0
- package/templates/ui/components/controls/color/color-model-slider.tsx +271 -0
- package/templates/ui/components/controls/color/color-opacity-input.tsx +94 -0
- package/templates/ui/components/controls/color/color-surface.tsx +194 -0
- package/templates/ui/components/controls/color/color-value-control.tsx +159 -0
- package/templates/ui/components/controls/color/color-value-utils.ts +170 -0
- package/templates/ui/components/controls/color/index.ts +10 -3
- package/templates/ui/components/controls/color/palette-control-controller.ts +407 -0
- package/templates/ui/components/controls/color/palette-control-layout.ts +14 -0
- package/templates/ui/components/controls/color/palette-control-types.ts +50 -0
- package/templates/ui/components/controls/color/palette-control-view.tsx +174 -0
- package/templates/ui/components/controls/color/palette-control.tsx +6 -544
- package/templates/ui/components/controls/color/style-guide-color-picker-color-utils.ts +39 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-controller.ts +370 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-hue-handlers.ts +66 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-interaction-state.ts +49 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-interactions.ts +2 -2
- package/templates/ui/components/controls/color/style-guide-color-picker-model.ts +125 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-parts.tsx +10 -707
- package/templates/ui/components/controls/color/style-guide-color-picker-surface-drag.ts +93 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-surface-geometry.ts +114 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-surface-preview.ts +45 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-types.ts +84 -0
- package/templates/ui/components/controls/color/style-guide-color-picker-view.tsx +69 -0
- package/templates/ui/components/controls/color/style-guide-color-picker.tsx +6 -495
- package/templates/ui/components/controls/curves/curves-control.tsx +4 -3
- package/templates/ui/components/controls/file-drop/file-drop-control.tsx +39 -515
- package/templates/ui/components/controls/file-drop/file-drop-empty-state.tsx +35 -0
- package/templates/ui/components/controls/file-drop/file-drop-file-list.tsx +160 -0
- package/templates/ui/components/controls/file-drop/file-drop-image-grid.tsx +175 -0
- package/templates/ui/components/controls/file-drop/file-drop-model.tsx +170 -0
- package/templates/ui/components/controls/file-drop/file-drop-single-preview.tsx +63 -0
- package/templates/ui/components/controls/file-drop/file-drop-types.ts +48 -0
- package/templates/ui/components/controls/file-drop/index.ts +2 -2
- package/templates/ui/components/controls/font-picker/font-picker-control.tsx +133 -906
- package/templates/ui/components/controls/font-picker/font-picker-footer.tsx +116 -0
- package/templates/ui/components/controls/font-picker/font-picker-list.tsx +194 -0
- package/templates/ui/components/controls/font-picker/font-picker-popover-content.tsx +191 -0
- package/templates/ui/components/controls/font-picker/font-picker-value.ts +222 -0
- package/templates/ui/components/controls/font-picker/index.ts +4 -1
- package/templates/ui/components/controls/font-picker/use-font-picker-preview-pipeline.ts +163 -0
- package/templates/ui/components/controls/font-picker/use-font-picker-virtual-list.ts +293 -0
- package/templates/ui/components/controls/gradient/gradient-control-utils.ts +2 -25
- package/templates/ui/components/controls/gradient/gradient-control.tsx +4 -464
- package/templates/ui/components/controls/gradient/gradient-stops-controller.ts +332 -0
- package/templates/ui/components/controls/gradient/gradient-stops-track.tsx +159 -0
- package/templates/ui/components/controls/vector/vector-control-types.ts +26 -0
- package/templates/ui/components/controls/vector/vector-control.tsx +10 -486
- package/templates/ui/components/controls/vector/vector-pad-field.tsx +211 -0
- package/templates/ui/components/controls/vector/vector-pad-geometry.ts +61 -0
- package/templates/ui/components/controls/vector/vector-pad-parts.tsx +72 -0
- package/templates/ui/components/controls/vector/vector-pad-variants.ts +20 -0
- package/templates/ui/components/controls/vector/vector-size-field.tsx +104 -0
- package/templates/ui/components/controls/vector/vector-value.ts +46 -0
- package/templates/ui/components/primitives/slider/slider-discrete-state.ts +181 -0
- package/templates/ui/components/primitives/slider/slider-marker-policy.ts +52 -0
- package/templates/ui/components/primitives/slider/slider-pointer-dragging.ts +87 -0
- package/templates/ui/components/primitives/slider/slider-runtime.ts +109 -0
- package/templates/ui/components/primitives/slider/slider-types.ts +21 -0
- package/templates/ui/components/primitives/slider/slider.tsx +2 -403
- package/templates/runtime/react/canvas-shell.test.tsx +0 -554
- package/templates/runtime/react/canvas-shell.tsx +0 -585
- package/templates/runtime/react/controls-panel.test.tsx +0 -5446
- package/templates/runtime/react/controls-panel.tsx +0 -3220
- package/templates/runtime/react/layers-panel.test.tsx +0 -487
- package/templates/runtime/react/layers-panel.tsx +0 -1348
- package/templates/runtime/react/timeline-panel.test.tsx +0 -751
- package/templates/runtime/react/timeline-panel.tsx +0 -3078
- package/templates/runtime/schema/define-toolcraft.test.ts +0 -1742
- package/templates/runtime/state/reducer.test.ts +0 -1703
- package/templates/runtime/testing/performance.test.ts +0 -3081
- package/templates/starter/e2e/app-browser-acceptance.spec.ts +0 -785
- package/templates/starter/src/app/starter-acceptance.test.ts +0 -10068
- package/templates/starter/src/app/starter-performance.test.ts +0 -1583
- package/templates/ui/components/controls/color/style-guide-color-picker-logic.ts +0 -490
- /package/templates/runtime/react/{storage-key-migration.ts → app-shell/storage-key-migration.ts} +0 -0
- /package/templates/runtime/react/{theme-runtime.tsx → app-shell/theme-runtime.tsx} +0 -0
- /package/templates/runtime/react/{curve-geometry.test.ts → controls-panel/__tests__/curve-geometry.test.ts} +0 -0
- /package/templates/runtime/react/{panel-host-config.ts → panel-host/panel-host-config.ts} +0 -0
- /package/templates/runtime/react/{panel-host-geometry.test.ts → panel-host/panel-host-geometry.test.ts} +0 -0
- /package/templates/runtime/react/{panel-host-geometry.ts → panel-host/panel-host-geometry.ts} +0 -0
|
@@ -1,1519 +1,58 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
ToolcraftSectionLayout,
|
|
8
|
-
} from "./types";
|
|
1
|
+
import { TOOLCRAFT_CHOICE_COMPONENT_CONTRACTS } from "./component-contracts.choices";
|
|
2
|
+
import { TOOLCRAFT_INPUT_COMPONENT_CONTRACTS } from "./component-contracts.inputs";
|
|
3
|
+
import { TOOLCRAFT_MEDIA_CUSTOM_COMPONENT_CONTRACTS } from "./component-contracts.media-custom";
|
|
4
|
+
import { TOOLCRAFT_RUNTIME_COMPONENT_CONTRACTS } from "./component-contracts.runtime";
|
|
5
|
+
import { TOOLCRAFT_VISUAL_COMPONENT_CONTRACTS } from "./component-contracts.visual";
|
|
6
|
+
import type { ToolcraftComponentContract } from "./types";
|
|
9
7
|
|
|
10
8
|
export type * from "./types";
|
|
11
9
|
|
|
12
10
|
export const TOOLCRAFT_COMPONENT_CONTRACTS = {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
"single numeric value",
|
|
19
|
-
"bounded continuous range",
|
|
20
|
-
"bounded stepped range",
|
|
21
|
-
"small semantic integer range",
|
|
22
|
-
],
|
|
23
|
-
useWhen: [
|
|
24
|
-
"Use Slider for one numeric value inside fixed min and max bounds.",
|
|
25
|
-
"Use Slider when dragging through approximate values is useful and every intermediate value is valid.",
|
|
26
|
-
"Use variant discrete only for small semantic integer domains where markers help choose positions.",
|
|
27
|
-
],
|
|
28
|
-
doNotReplaceWith: [
|
|
29
|
-
"Do not use Slider for finite named options; use Select or Segmented.",
|
|
30
|
-
"Do not use two Slider controls for a lower/upper range; use RangeSlider or RangeInput.",
|
|
31
|
-
"Do not use Slider as a detached opacity field for a color entity; use ColorOpacity.",
|
|
32
|
-
],
|
|
33
|
-
acceptableAlternatives: [
|
|
34
|
-
"Use Select for small named option sets.",
|
|
35
|
-
"Use RangeSlider or RangeInput for from/to ranges.",
|
|
36
|
-
],
|
|
37
|
-
layoutConstraints: [
|
|
38
|
-
"Schema sliders stay stacked at full width.",
|
|
39
|
-
"Only FontPicker may pair its internal letter-spacing and line-height sliders.",
|
|
40
|
-
],
|
|
41
|
-
requiredAcceptance: [
|
|
42
|
-
"Prove dragging the slider changes product output or the intended runtime side effect while the drag is in progress, not only after pointer release, blur, Apply, or a final commit.",
|
|
43
|
-
"For discrete sliders, prove the discrete variant renders markers and dragging remains smooth.",
|
|
44
|
-
],
|
|
45
|
-
}),
|
|
46
|
-
aiUsageRules: [
|
|
47
|
-
"Sliders are live canvas controls: dragging must update runtime state and product output in real time by default.",
|
|
48
|
-
"Do not implement slider values as deferred local drafts, Apply-only updates, pointer-up-only commits, or renderer changes that appear only after the user asks again.",
|
|
49
|
-
"Slider performance coverage must use a real control-drag scenario; control-change coverage is not enough to prove live canvas feedback or drag smoothness.",
|
|
50
|
-
"If a live slider causes jank, optimize the renderer path first: update uniforms or stable buffers, cache expensive inputs, coalesce preview work to requestAnimationFrame, cancel stale async renders, move heavy work off React, or switch renderer strategy.",
|
|
51
|
-
"Only in an extreme documented performance ceiling may a slider use a degraded live preview or delayed heavy refinement; the user must still see immediate canvas feedback while dragging and the worklog must record the measured reason.",
|
|
52
|
-
"Slider step means numeric snapping only; it does not make the slider visually discrete by itself.",
|
|
53
|
-
"Classify every stepped slider as stepped continuous or visual discrete before writing the schema.",
|
|
54
|
-
'Small semantic integer domains such as rows, cols, gaps, jitter, counts, levels, bands, passes, points, tiles, and segments must use variant: "discrete".',
|
|
55
|
-
'Finite animation step domains such as flip depth, character count, glyph steps, and frame steps must use variant: "discrete" when the marker count stays within the Toolcraft visual budget.',
|
|
56
|
-
"Large or precision stepped ranges such as speed, FPS, rate, duration, density, size, and intensity stay visually continuous even when they declare step.",
|
|
57
|
-
"Use slider unit only for real measurement suffixes such as %, px, °, s, ms, fps, rows/cols, or similar domain units.",
|
|
58
|
-
"Do not use unit for repeated entity nouns already named by the section or label, such as Letters + letters, Shape Density / Count + shapes, Words + words, Symbols + symbols, Items + items, Particles + particles, or Layers + layers.",
|
|
59
|
-
'Do not use unit: "x"; scale, multiplier, intensity, opacity, strength, depth, and shader amount sliders display plain numbers unless a real measurement unit applies.',
|
|
60
|
-
"When the value needs an entity noun to make sense, improve the label or section title instead of appending that noun as the value unit.",
|
|
61
|
-
"Compact symbol/CSS units render tight, such as 70%, 24px, and 8s; word units render with a space, such as 5 cols, when they are truly needed.",
|
|
62
|
-
"Slider valueLabel is editable only when it contains a numeric value; textual state labels such as Normal are display-only and must not expose hover or click editing affordances.",
|
|
63
|
-
"Schema sliders render stacked at full width; do not put sliders in two-column inline layout groups.",
|
|
64
|
-
"The fontPicker component is the only built-in exception with two internal footer sliders for letter spacing and line height.",
|
|
65
|
-
"For a small named option set, prefer Select or Segmented instead of forcing a discrete Slider.",
|
|
66
|
-
'Specs, plans, and app-schema tests must assert explicit discrete sliders render as variant: "discrete" with markers derived from min, max, and step.',
|
|
67
|
-
'Browser verification can inspect [data-slot="slider"][data-variant="discrete"] plus slider markers to prove the Toolcraft component variant rendered.',
|
|
68
|
-
"Visual discrete sliders must still drag smoothly; browser performance tests should use expectToolcraftDiscreteSliderDragSmoothness for real pointer drag.",
|
|
69
|
-
"Use visibleWhen for sliders that are meaningful only in some mode/type/source/include/count states; inactive branches should disappear so the panel shows only controls usable in the current state.",
|
|
70
|
-
"Do not use schema disabled: true or disabledWhen for product sliders; product panels should show only controls usable in the current state. Use visibleWhen for unavailable product states instead of rendering disabled controls.",
|
|
71
|
-
"Do not leave an inactive conditional slider visible while making the renderer ignore it; hide it with visibleWhen.",
|
|
72
|
-
],
|
|
73
|
-
},
|
|
74
|
-
rangeSlider: {
|
|
75
|
-
...control("rangeSlider", "RangeSlider", "grouped", "required"),
|
|
76
|
-
decisionCatalog: decisionCatalog({
|
|
77
|
-
strictness: "exact-owner",
|
|
78
|
-
ownsValueModel: [
|
|
79
|
-
"numeric lower and upper bounds",
|
|
80
|
-
"from/to numeric range",
|
|
81
|
-
"two-thumb bounded interval",
|
|
82
|
-
],
|
|
83
|
-
useWhen: [
|
|
84
|
-
"Use RangeSlider when users edit lower and upper bounds on the same numeric scale.",
|
|
85
|
-
"Use RangeSlider when the relationship between the two values matters visually.",
|
|
86
|
-
],
|
|
87
|
-
doNotReplaceWith: [
|
|
88
|
-
"Do not replace RangeSlider with two independent Slider controls.",
|
|
89
|
-
"Do not place RangeSlider beside another slider in an inline row.",
|
|
90
|
-
],
|
|
91
|
-
acceptableAlternatives: [
|
|
92
|
-
"Use RangeInput when manual exact text entry matters more than dragging handles.",
|
|
93
|
-
],
|
|
94
|
-
layoutConstraints: [
|
|
95
|
-
"RangeSlider is always full-width and stacked.",
|
|
96
|
-
"Default lower and upper values must be different.",
|
|
97
|
-
],
|
|
98
|
-
requiredAcceptance: [
|
|
99
|
-
"Prove dragging rangeSlider.lower and rangeSlider.upper both affect product output while the drag is in progress, not only after pointer release, blur, Apply, or a final commit.",
|
|
100
|
-
],
|
|
101
|
-
}),
|
|
102
|
-
aiUsageRules: [
|
|
103
|
-
"Range sliders are live canvas controls: dragging either thumb must update runtime state and product output in real time by default.",
|
|
104
|
-
"Do not implement range slider values as deferred local drafts, Apply-only updates, pointer-up-only commits, or renderer changes that appear only after the user asks again.",
|
|
105
|
-
"Range slider performance coverage must use a real control-drag scenario; control-change coverage is not enough to prove live canvas feedback or drag smoothness.",
|
|
106
|
-
"If a live range slider causes jank, optimize the renderer path first: update uniforms or stable buffers, cache expensive inputs, coalesce preview work to requestAnimationFrame, cancel stale async renders, move heavy work off React, or switch renderer strategy.",
|
|
107
|
-
"Only in an extreme documented performance ceiling may a range slider use a degraded live preview or delayed heavy refinement; the user must still see immediate canvas feedback while dragging and the worklog must record the measured reason.",
|
|
108
|
-
"Range slider step means numeric snapping only; it does not make the range slider visually discrete by itself.",
|
|
109
|
-
"Classify every stepped range slider as stepped continuous or visual discrete before writing the schema.",
|
|
110
|
-
'Small semantic integer domains such as rows, cols, gaps, jitter, counts, levels, bands, passes, points, tiles, and segments must use variant: "discrete".',
|
|
111
|
-
'Finite animation step domains such as flip depth, character count, glyph steps, and frame steps must use variant: "discrete" when the marker count stays within the Toolcraft visual budget.',
|
|
112
|
-
"Large or precision stepped ranges such as speed, FPS, rate, duration, density, size, and intensity stay visually continuous even when they declare step.",
|
|
113
|
-
"Use rangeSlider unit only for real measurement suffixes; do not use it for repeated entity nouns already named by the section or label, and do not use x as a unit.",
|
|
114
|
-
"When a range label needs an entity noun to make sense, improve the label or section title instead of appending that noun as the value unit.",
|
|
115
|
-
"Compact symbol/CSS units render tight, such as 20% – 80% or 12px – 48px; word units render with a space when truly needed.",
|
|
116
|
-
"RangeSlider is always a full-width two-thumb control; never place it in an inline two-column layout group with another slider or range slider.",
|
|
117
|
-
"RangeSlider defaultValue must start with different lower and upper values so the two-thumb control does not collapse into a single-value slider.",
|
|
118
|
-
"Manual range value editing accepts common separators such as slash, hyphen, spaces, and dashes, including when values include unit suffixes such as 30%-150% or 30% - 90%; do not create custom parsers for RangeSlider labels.",
|
|
119
|
-
'Specs, plans, and app-schema tests must assert explicit discrete range sliders render as variant: "discrete" with markers derived from min, max, and step.',
|
|
120
|
-
"Visual discrete sliders must still drag smoothly; browser performance tests should use expectToolcraftDiscreteSliderDragSmoothness for real pointer drag.",
|
|
121
|
-
"Use visibleWhen for range sliders that are meaningful only in some mode/type/source/include/count states; inactive branches should disappear so the panel shows only controls usable in the current state.",
|
|
122
|
-
"Do not use schema disabled: true or disabledWhen for product range sliders; product panels should show only controls usable in the current state. Use visibleWhen for unavailable product states instead of rendering disabled controls.",
|
|
123
|
-
"Do not leave an inactive conditional range slider visible while making the renderer ignore it; hide it with visibleWhen.",
|
|
124
|
-
"Acceptance must prove both rangeSlider.lower and rangeSlider.upper change the product output; testing one handle is not enough.",
|
|
125
|
-
],
|
|
126
|
-
},
|
|
127
|
-
select: {
|
|
128
|
-
...control("select", "Select", "grouped", "required"),
|
|
129
|
-
decisionCatalog: decisionCatalog({
|
|
130
|
-
strictness: "best-fit",
|
|
131
|
-
ownsValueModel: [
|
|
132
|
-
"finite single selection",
|
|
133
|
-
"long option labels",
|
|
134
|
-
"many options",
|
|
135
|
-
"segmented fallback",
|
|
136
|
-
],
|
|
137
|
-
useWhen: [
|
|
138
|
-
"Use Select for finite choices with long labels, many options, or values that would not fit in Segmented.",
|
|
139
|
-
"Use Select when a dropdown choice is more readable than a row of segmented cells.",
|
|
140
|
-
],
|
|
141
|
-
doNotReplaceWith: [
|
|
142
|
-
"Do not use Select to recreate FontPicker, Gradient, ImagePicker, FileDrop, Curves, Vector, or Palette value models.",
|
|
143
|
-
],
|
|
144
|
-
acceptableAlternatives: [
|
|
145
|
-
"Use Segmented for two to four short closely related options that fit without clipping.",
|
|
146
|
-
],
|
|
147
|
-
layoutConstraints: [
|
|
148
|
-
"Standalone Select controls render stacked full-width with the label above the dropdown; do not use the compact side-label row with label left and dropdown right.",
|
|
149
|
-
"Prefer compact two-column inline layout only for related short Select pairs that tune one workflow or entity.",
|
|
150
|
-
"Use vertical one-select-per-row layout for single Select controls and as the fallback when a Select pair label, selected value, or option text would clip, truncate, or lose internal padding in the compact row.",
|
|
151
|
-
"If a compact Select pair falls back to vertical layout, record the fit reason in the spec or worklog.",
|
|
152
|
-
],
|
|
153
|
-
requiredAcceptance: [
|
|
154
|
-
"Prove every visible option or representative option set changes product output or interpreted product state.",
|
|
155
|
-
],
|
|
156
|
-
}),
|
|
157
|
-
},
|
|
158
|
-
segmented: {
|
|
159
|
-
...control("segmented", "Segmented", "grouped", "required"),
|
|
160
|
-
decisionCatalog: decisionCatalog({
|
|
161
|
-
strictness: "best-fit",
|
|
162
|
-
ownsValueModel: [
|
|
163
|
-
"compact finite mode choice",
|
|
164
|
-
"two to four short related options",
|
|
165
|
-
"single-row mode toggle",
|
|
166
|
-
],
|
|
167
|
-
useWhen: [
|
|
168
|
-
"Use Segmented for compact mode choices where every cell keeps internal padding.",
|
|
169
|
-
"Use Segmented when the options are short, closely related, and easier to compare side by side.",
|
|
170
|
-
],
|
|
171
|
-
doNotReplaceWith: [
|
|
172
|
-
"Do not use Segmented for long labels, many options, or values that clip.",
|
|
173
|
-
"Do not use Segmented for actions; use buttons or panelActions.",
|
|
174
|
-
],
|
|
175
|
-
acceptableAlternatives: [
|
|
176
|
-
"Use Select when options are long, numerous, or break segmented cell padding.",
|
|
177
|
-
],
|
|
178
|
-
layoutConstraints: [
|
|
179
|
-
"Keep text segmented controls to at most four options and compact labels.",
|
|
180
|
-
"Segmented controls are full-width controls and must not be placed in two-column inline or half-width layout groups.",
|
|
181
|
-
"Fallback to Select when cells collide, clip, or lose padding.",
|
|
182
|
-
],
|
|
183
|
-
requiredAcceptance: [
|
|
184
|
-
"Prove every visible segment changes the relevant product mode or output.",
|
|
185
|
-
"Browser verification must treat clipped or paddingless cells as broken.",
|
|
186
|
-
],
|
|
187
|
-
}),
|
|
188
|
-
aiUsageRules: [
|
|
189
|
-
"Use Segmented only for compact mode choices where every cell keeps its internal padding.",
|
|
190
|
-
"Do not place Segmented beside Switch, Color, Select, or another control in an inline row; use Select when a finite choice must occupy a half-width column.",
|
|
191
|
-
"If a segmented control is too wide, first shorten option labels; if the compact labels still exceed the width budget, use Select because it has the same selection mechanics without broken cells.",
|
|
192
|
-
"Generated schemas should keep text segmented controls to at most four options, no option label longer than nine characters, and no more than twenty-four total option-label characters.",
|
|
193
|
-
"Browser verification must treat collided, clipped, or paddingless segmented cells as a broken component and switch to shorter labels or Select.",
|
|
194
|
-
],
|
|
195
|
-
},
|
|
196
|
-
switch: {
|
|
197
|
-
...control("switch", "Switch", "grouped", "required"),
|
|
198
|
-
decisionCatalog: decisionCatalog({
|
|
199
|
-
strictness: "best-fit",
|
|
200
|
-
ownsValueModel: [
|
|
201
|
-
"immediate binary setting",
|
|
202
|
-
"on/off product behavior",
|
|
203
|
-
"enabled/disabled runtime option",
|
|
204
|
-
],
|
|
205
|
-
useWhen: [
|
|
206
|
-
"Use Switch for a binary setting that applies immediately.",
|
|
207
|
-
"Use Switch for options such as Glow, Loop, CRT, Background, or Guides.",
|
|
208
|
-
],
|
|
209
|
-
doNotReplaceWith: [
|
|
210
|
-
"Do not use Switch for more than two options.",
|
|
211
|
-
"Do not use Switch for destructive actions or commands that need confirmation.",
|
|
212
|
-
],
|
|
213
|
-
acceptableAlternatives: [
|
|
214
|
-
"Use Checkbox when the option is an explicit inclusion flag.",
|
|
215
|
-
"Use Select or Segmented for more than two options.",
|
|
216
|
-
],
|
|
217
|
-
layoutConstraints: [
|
|
218
|
-
"Two adjacent Switch controls for the same product entity must share one inline row when both labels fit; the runtime auto-pairs safe adjacent switches by target entity when no explicit layout group is needed.",
|
|
219
|
-
],
|
|
220
|
-
requiredAcceptance: [
|
|
221
|
-
"Prove toggling the switch changes the product output or runtime behavior.",
|
|
222
|
-
],
|
|
223
|
-
}),
|
|
224
|
-
aiUsageRules: [
|
|
225
|
-
'Switch labels name the setting context only; do not prefix labels with "Enable" or "Disable" because the switch already communicates on/off behavior.',
|
|
226
|
-
'Use labels such as "CRT", "Background", "Glow", or "Loop" instead of "Enable CRT" or "Disable background".',
|
|
227
|
-
"Two adjacent Switch controls for the same product entity must share one inline row when every visible label fits without truncation. Keep paired labels to short one- or two-word names; the runtime auto-pairs safe adjacent switches by target entity, and generated schemas should stack switches only when any label would truncate.",
|
|
228
|
-
"When the nearest section title already names the switch context, do not duplicate that title as the visible switch label. Use label false for a visual-only toggle and keep the meaning in target/description.",
|
|
229
|
-
'A Switch may share an inline row with one related parameter control when the visible switch label is short enough to fit. That row uses equal-width columns and the same horizontal column gap as paired Select controls; never shrink the switch column to intrinsic width. The non-switch parameter uses label false in that row; if its label is needed, stack the controls instead. In section-owned rows, use a short visible switch label such as "Include" instead of repeating the section title, such as "Include background" inside Background.',
|
|
230
|
-
],
|
|
231
|
-
},
|
|
232
|
-
checkbox: {
|
|
233
|
-
...control("checkbox", "Checkbox", "grouped", "required"),
|
|
234
|
-
decisionCatalog: decisionCatalog({
|
|
235
|
-
strictness: "best-fit",
|
|
236
|
-
ownsValueModel: [
|
|
237
|
-
"explicit optional flag",
|
|
238
|
-
"included/excluded choice",
|
|
239
|
-
"binary checklist state",
|
|
240
|
-
],
|
|
241
|
-
useWhen: [
|
|
242
|
-
"Use Checkbox when the product meaning is an explicit optional flag or inclusion choice.",
|
|
243
|
-
],
|
|
244
|
-
doNotReplaceWith: [
|
|
245
|
-
"Do not use Checkbox for immediate setting toggles that read more naturally as Switch.",
|
|
246
|
-
"Do not use Checkbox for commands.",
|
|
247
|
-
],
|
|
248
|
-
acceptableAlternatives: [
|
|
249
|
-
"Use Switch for immediate on/off settings.",
|
|
250
|
-
"Use Select or Segmented for more than two options.",
|
|
251
|
-
],
|
|
252
|
-
layoutConstraints: [
|
|
253
|
-
"Two adjacent Checkbox controls for the same product entity must share one inline row when both labels fit; the runtime auto-pairs safe adjacent checkboxes by target entity when no explicit layout group is needed.",
|
|
254
|
-
],
|
|
255
|
-
requiredAcceptance: [
|
|
256
|
-
"Prove checking and unchecking changes product output or runtime behavior.",
|
|
257
|
-
],
|
|
258
|
-
}),
|
|
259
|
-
aiUsageRules: [
|
|
260
|
-
'Checkbox labels name the setting context only; do not prefix labels with "Enable" or "Disable" because the checkbox already communicates enabled/selected state.',
|
|
261
|
-
'Use labels such as "Transparent background", "Guides", or "Loop" instead of "Enable transparent background".',
|
|
262
|
-
"When the nearest section title already names the checkbox context, do not duplicate that title as the visible checkbox label. Use label false for a visual-only checkbox and keep the meaning in target/description.",
|
|
263
|
-
"Two adjacent Checkbox controls for the same product entity must share one inline row when every visible label fits without truncation. Keep paired labels to short one- or two-word names; the runtime auto-pairs safe adjacent checkboxes by target entity, and generated schemas should stack checkboxes only when any label would truncate.",
|
|
264
|
-
"A Checkbox may share an inline row with one related parameter control when the visible checkbox label is short enough to fit. That row uses equal-width columns and the same horizontal column gap as paired Select controls; never shrink the checkbox column to intrinsic width. The non-checkbox parameter uses label false in that row; if its label is needed, stack the controls instead. Hide the checkbox label when the section title provides the visible context.",
|
|
265
|
-
],
|
|
266
|
-
},
|
|
267
|
-
colorOpacity: {
|
|
268
|
-
...control("colorOpacity", "ColorOpacity", "standalone", "component-owned"),
|
|
269
|
-
decisionCatalog: decisionCatalog({
|
|
270
|
-
strictness: "exact-owner",
|
|
271
|
-
ownsValueModel: [
|
|
272
|
-
"color plus opacity for one entity",
|
|
273
|
-
"hex color and percent opacity",
|
|
274
|
-
],
|
|
275
|
-
useWhen: [
|
|
276
|
-
"Use ColorOpacity when one product entity owns both a color and opacity.",
|
|
277
|
-
],
|
|
278
|
-
doNotReplaceWith: [
|
|
279
|
-
"Do not split ColorOpacity into separate Color and opacity Slider/Input controls.",
|
|
280
|
-
],
|
|
281
|
-
acceptableAlternatives: [
|
|
282
|
-
"Use Color only when opacity is not editable.",
|
|
283
|
-
"Use Gradient when the entity is a color transition or gradient fill.",
|
|
284
|
-
],
|
|
285
|
-
layoutConstraints: [
|
|
286
|
-
"ColorOpacity stays stacked and does not share inline color rows.",
|
|
287
|
-
],
|
|
288
|
-
requiredAcceptance: [
|
|
289
|
-
"Prove colorOpacity.hex and colorOpacity.opacity both affect product output.",
|
|
290
|
-
],
|
|
291
|
-
}),
|
|
292
|
-
aiUsageRules: [
|
|
293
|
-
"Use ColorOpacity when one product entity needs both a color and an opacity value, such as text color, shadow color, glow color, overlay color, or stroke color.",
|
|
294
|
-
"Do not split ColorOpacity into a separate Color plus Slider/Input for opacity; use type: \"colorOpacity\" so the color popover and percent input stay visually connected.",
|
|
295
|
-
"ColorOpacity is the only color control variant that may expose opacity in the color picker popover; plain Color popovers hide opacity controls.",
|
|
296
|
-
"Use one object value with hex and opacity. Renderers and exports must consume both parts.",
|
|
297
|
-
"Do not place ColorOpacity in inline two-column layout groups. If either color control has opacity, keep the controls stacked.",
|
|
298
|
-
"Only plain Color controls without opacity may render in two-column color rows.",
|
|
299
|
-
"Acceptance must prove colorOpacity.hex and colorOpacity.opacity both affect the product output; testing only the swatch or only runtime state is not enough.",
|
|
300
|
-
],
|
|
301
|
-
},
|
|
302
|
-
text: {
|
|
303
|
-
...control("text", "TextInput", "grouped", "required"),
|
|
304
|
-
decisionCatalog: decisionCatalog({
|
|
305
|
-
strictness: "best-fit",
|
|
306
|
-
ownsValueModel: [
|
|
307
|
-
"short single-line text",
|
|
308
|
-
"single-line content",
|
|
309
|
-
"single-line setting value",
|
|
310
|
-
],
|
|
311
|
-
useWhen: [
|
|
312
|
-
"Use TextInput for short names, button labels, titles, captions, tokens, compact prompts, and small setting strings.",
|
|
313
|
-
"Use commitMode content for real product content and commitMode setting for configuration-like values.",
|
|
314
|
-
],
|
|
315
|
-
doNotReplaceWith: [
|
|
316
|
-
"Do not use TextInput for long multiline content; use CodeTextarea.",
|
|
317
|
-
],
|
|
318
|
-
acceptableAlternatives: [
|
|
319
|
-
"Use CodeTextarea for multiline or long structured content.",
|
|
320
|
-
"Use Select for finite choices.",
|
|
321
|
-
],
|
|
322
|
-
layoutConstraints: [
|
|
323
|
-
"Short numeric/text pairs can share inline rows when they tune one product meaning.",
|
|
324
|
-
],
|
|
325
|
-
requiredAcceptance: [
|
|
326
|
-
"Prove text edits change product content or the intended setting at the correct commit timing.",
|
|
327
|
-
],
|
|
328
|
-
}),
|
|
329
|
-
aiUsageRules: [
|
|
330
|
-
"TextInput owns short single-line product text: button labels, labels on the canvas, names, titles, captions, badges, short tokens, and compact prompts.",
|
|
331
|
-
'TextInput commitMode defaults to "content": text content, prompts, names, tokens, titles, and instructions apply while typing.',
|
|
332
|
-
'Use commitMode: "setting" for text inputs that edit settings such as font size, numeric-like style values, dimensions, ids, or configuration fields; setting text commits on blur or Enter.',
|
|
333
|
-
"Canvas width and Canvas height are runtime editable-size fields and always commit on blur or Enter like editor size fields.",
|
|
334
|
-
],
|
|
335
|
-
},
|
|
336
|
-
rangeInput: {
|
|
337
|
-
...control("rangeInput", "RangeInput", "grouped", "required"),
|
|
338
|
-
decisionCatalog: decisionCatalog({
|
|
339
|
-
strictness: "exact-owner",
|
|
340
|
-
ownsValueModel: [
|
|
341
|
-
"manual lower and upper values",
|
|
342
|
-
"from/to text range",
|
|
343
|
-
"compact paired range input",
|
|
344
|
-
],
|
|
345
|
-
useWhen: [
|
|
346
|
-
"Use RangeInput when users need to type or inspect a lower and upper bound more than drag them.",
|
|
347
|
-
],
|
|
348
|
-
doNotReplaceWith: [
|
|
349
|
-
"Do not replace RangeInput with two unrelated TextInput controls for one range.",
|
|
350
|
-
],
|
|
351
|
-
acceptableAlternatives: [
|
|
352
|
-
"Use RangeSlider when dragging the range relationship is the primary interaction.",
|
|
353
|
-
],
|
|
354
|
-
layoutConstraints: [
|
|
355
|
-
"Keep the two range fields together as one compound control.",
|
|
356
|
-
],
|
|
357
|
-
requiredAcceptance: [
|
|
358
|
-
"Prove rangeInput.start and rangeInput.end both affect product output.",
|
|
359
|
-
],
|
|
360
|
-
}),
|
|
361
|
-
aiUsageRules: [
|
|
362
|
-
"RangeInput is a compound control; acceptance must prove rangeInput.start and rangeInput.end both affect the product output.",
|
|
363
|
-
"Do not accept a range input test that edits only the first field or only checks runtime state.",
|
|
364
|
-
],
|
|
365
|
-
},
|
|
366
|
-
actions: {
|
|
367
|
-
...control("actions", "Actions", "grouped", "required"),
|
|
368
|
-
decisionCatalog: decisionCatalog({
|
|
369
|
-
strictness: "best-fit",
|
|
370
|
-
ownsValueModel: [
|
|
371
|
-
"local section action",
|
|
372
|
-
"small contextual command",
|
|
373
|
-
"non-sticky workflow command",
|
|
374
|
-
"entity-scoped command group",
|
|
375
|
-
],
|
|
376
|
-
useWhen: [
|
|
377
|
-
"Use Actions for local commands inside a control section that affect the nearby entity.",
|
|
378
|
-
"Use Actions for section-scoped commands such as Randomize palette, Normalize weights, Sort glyphs, Clear selection, Duplicate item, or Reset current entity.",
|
|
379
|
-
],
|
|
380
|
-
doNotReplaceWith: [
|
|
381
|
-
"Do not use Actions for final product export, copy, generate, apply, or download actions.",
|
|
382
|
-
"Do not use Actions for global reset; the panel header owns reset.",
|
|
383
|
-
"Do not use Actions for timeline transport such as Play, Pause, Resume, Restart, or Scrub.",
|
|
384
|
-
],
|
|
385
|
-
acceptableAlternatives: [
|
|
386
|
-
"Use panelActions for sticky product delivery actions.",
|
|
387
|
-
"Use item-level icon buttons inside custom controls for local item remove/reorder commands.",
|
|
388
|
-
"Use the top TimelinePanel for animation transport commands.",
|
|
389
|
-
],
|
|
390
|
-
layoutConstraints: [
|
|
391
|
-
"Keep local actions close to the entity they affect.",
|
|
392
|
-
"Keep action labels short and scoped by the section title; prefer Randomize, Clear, Sort, Normalize, Duplicate, or Reset when the section already names the target.",
|
|
393
|
-
"Do not set an Actions control label to the exact same visible text as its only button; use a short one- or two-word context label such as Ink wash, Palette action, or Current layer while the button keeps the command verb.",
|
|
394
|
-
"Actions never use a side-label layout. If a visible label exists, it sits above the buttons.",
|
|
395
|
-
"Actions buttons render as a two-column grid. One visible button occupies the left half of the section; two buttons occupy one half each; more than two buttons wrap into additional 50% cells.",
|
|
396
|
-
"Do not center or right-align a partial final Actions row; an odd trailing button stays in the left 50% cell.",
|
|
397
|
-
],
|
|
398
|
-
requiredAcceptance: [
|
|
399
|
-
"Prove each action dispatches the intended command or product side effect for the nearby entity only.",
|
|
400
|
-
],
|
|
401
|
-
}),
|
|
402
|
-
commands: ["controls.reset", "controls.apply"],
|
|
403
|
-
stateMode: "command-only",
|
|
404
|
-
aiUsageRules: [
|
|
405
|
-
"Use Actions for local commands inside the current section when the command affects only the nearby entity or workflow step.",
|
|
406
|
-
"Good Actions examples: Randomize palette, Normalize weights, Sort glyphs, Clear selection, Duplicate item, Reset current layer, Reset current stop, or Shuffle shades.",
|
|
407
|
-
"Do not use Actions for final product delivery actions; use sticky panelActions for Export, Copy, Download, Generate, or Apply.",
|
|
408
|
-
"Do not use Actions for global reset; the controls panel header owns global reset.",
|
|
409
|
-
"Do not use Actions for animation transport; Play, Pause, Resume, Restart, and Scrub belong to the top timeline when timeline behavior exists.",
|
|
410
|
-
"For a single visible Actions button, the control label and button label must not be identical; make the control label a concise context and the button label the command.",
|
|
411
|
-
"Render the Actions label above the buttons; do not put the label on the left with buttons on the right.",
|
|
412
|
-
"Render Actions buttons in 50% cells: one button uses the left half, two buttons fill one row, and larger groups continue in two columns.",
|
|
413
|
-
"Do not stretch an odd trailing Actions button full-width.",
|
|
414
|
-
'For local reset-like actions, use product-specific values such as "reset-current-layer" or "reset-palette" and handle them through ToolcraftApp onPanelAction; do not use a bare "reset" value unless the action intentionally runs controls.reset.',
|
|
415
|
-
"Acceptance and browser tests must click each Actions button and prove the product output or runtime state for the nearby entity changed.",
|
|
416
|
-
],
|
|
417
|
-
},
|
|
418
|
-
collectionActions: {
|
|
419
|
-
...control("collectionActions", "CollectionActions", "standalone", "component-owned"),
|
|
420
|
-
decisionCatalog: decisionCatalog({
|
|
421
|
-
strictness: "exact-owner",
|
|
422
|
-
ownsValueModel: [
|
|
423
|
-
"repeatable product entity collection",
|
|
424
|
-
"add/remove product items",
|
|
425
|
-
"dynamic list of visible controls",
|
|
426
|
-
"canvas-backed collection size",
|
|
427
|
-
],
|
|
428
|
-
useWhen: [
|
|
429
|
-
"Use CollectionActions when users can add or remove repeated product entities such as colors, glyphs, symbols, points, rules, variants, or object entries.",
|
|
430
|
-
"Use CollectionActions instead of a count Slider when the user edits the actual set of items rather than only a numeric amount.",
|
|
431
|
-
],
|
|
432
|
-
doNotReplaceWith: [
|
|
433
|
-
"Do not use Slider to add or remove real collection items.",
|
|
434
|
-
"Do not use plain Actions for add/remove collection ownership; Actions are local commands, not collection state owners.",
|
|
435
|
-
"Do not use CollectionActions for panel-only lists that do not affect canvas preview or export.",
|
|
436
|
-
],
|
|
437
|
-
acceptableAlternatives: [
|
|
438
|
-
"Use fileDrop multiple when the repeated entities are uploaded images.",
|
|
439
|
-
"Use Gradient when the repeated entities are gradient stops inside an adjustable gradient.",
|
|
440
|
-
"Use customControl only when the repeated entity needs interactions no built-in collection item control can express.",
|
|
441
|
-
],
|
|
442
|
-
layoutConstraints: [
|
|
443
|
-
"CollectionActions sits at the start of its section, renders the collection label on the left, and keeps remove/add icon buttons together on the right.",
|
|
444
|
-
"Homogeneous repeated item controls do not render visible per-item labels when the collection label already names the group.",
|
|
445
|
-
"Collection item controls follow normal density rules: plain color items use equal 50% columns when they fit, while color+opacity items stay stacked.",
|
|
446
|
-
"CollectionActions is a compound control and follows content-width compound divider rules when sharing a section with sibling controls.",
|
|
447
|
-
"recommendedMaxItems is an agent/layout/performance hint, not a hard add limit; hardMaxItems is allowed only for real algorithm, format, API, export, or proven performance limits.",
|
|
448
|
-
],
|
|
449
|
-
requiredAcceptance: [
|
|
450
|
-
"Prove plus adds a runtime item and that the new item appears in or affects canvas preview and export.",
|
|
451
|
-
"Prove minus removes a runtime item and that the removed item disappears from or stops affecting canvas preview and export.",
|
|
452
|
-
"Prove minItems prevents deleting below the minimum and recommendedMaxItems does not silently block adding more items.",
|
|
453
|
-
],
|
|
454
|
-
}),
|
|
455
|
-
stateMode: "controlled",
|
|
456
|
-
aiUsageRules: [
|
|
457
|
-
"Use CollectionActions for repeatable product entities whose actual item list can grow or shrink.",
|
|
458
|
-
"Adding or removing collection items must update the runtime target array consumed by the renderer and export; do not add panel-only items.",
|
|
459
|
-
"Do not model add/remove item behavior with a Slider count when users need to edit the actual items.",
|
|
460
|
-
"recommendedMaxItems is advisory only and must not disable the plus button. Use hardMaxItems only when a real product, algorithm, API, export, or measured performance limit requires it.",
|
|
461
|
-
"CollectionActions item controls use built-in controls whenever possible, such as Color, ColorOpacity, TextInput, Select, Segmented, Slider, Switch, Checkbox, RangeInput, or FontPicker.",
|
|
462
|
-
"Use FontPicker as the collection item control when each repeated item is a typography/text-style entity; do not split its font, color, opacity, size, case, letter-spacing, or line-height into sibling collection fields.",
|
|
463
|
-
"Do not add visible labels like Color 1, Color 2, Item 1, or Item 2 for homogeneous collection items when the collection label already explains the group.",
|
|
464
|
-
"Use compact half-width item layout whenever the child control is allowed to fit in a half row; color items without opacity are the default two-column case.",
|
|
465
|
-
"Acceptance must add and remove items through the browser UI and prove canvas/export output follows the changed collection.",
|
|
466
|
-
],
|
|
467
|
-
},
|
|
468
|
-
panelActions: {
|
|
469
|
-
...control("panelActions", "PanelActions", "standalone", "component-owned"),
|
|
470
|
-
decisionCatalog: decisionCatalog({
|
|
471
|
-
strictness: "exact-owner",
|
|
472
|
-
ownsValueModel: [
|
|
473
|
-
"sticky final product action",
|
|
474
|
-
"export action",
|
|
475
|
-
"copy action",
|
|
476
|
-
"generate action",
|
|
477
|
-
"apply action",
|
|
478
|
-
],
|
|
479
|
-
useWhen: [
|
|
480
|
-
"Use panelActions for final product actions such as Export, Copy, Generate, Apply, or Download.",
|
|
481
|
-
],
|
|
482
|
-
doNotReplaceWith: [
|
|
483
|
-
"Do not place final product action buttons on the canvas.",
|
|
484
|
-
"Do not use regular section Actions for final sticky export or generate actions.",
|
|
485
|
-
"Do not duplicate global Reset in panelActions.",
|
|
486
|
-
],
|
|
487
|
-
acceptableAlternatives: [
|
|
488
|
-
"Use Actions only for local section commands.",
|
|
489
|
-
],
|
|
490
|
-
layoutConstraints: [
|
|
491
|
-
"Footer actions are one compact sticky group with secondary on the left and primary on the right.",
|
|
492
|
-
],
|
|
493
|
-
requiredAcceptance: [
|
|
494
|
-
"Prove panel actions execute real product side effects such as exported bytes, clipboard payload, or generated output.",
|
|
495
|
-
"For async panelActions, prove the sticky footer top accent indicator is visible while the returned Promise is pending, advances when reportProgress is called, and hides after it settles.",
|
|
496
|
-
],
|
|
497
|
-
}),
|
|
498
|
-
aiUsageRules: [
|
|
499
|
-
"Use panelActions only for sticky footer product actions such as Generate, Export, Copy, or Download.",
|
|
500
|
-
"Do not use panelActions for resetting controls; the controls panel header owns Reset controls.",
|
|
501
|
-
"Handle product-specific panelActions through ToolcraftApp onPanelAction.",
|
|
502
|
-
"Async product actions such as Export, Download, Copy, Generate, or Apply must return the real Promise from onPanelAction and report progress through the onPanelAction reportProgress callback.",
|
|
503
|
-
"The sticky footer top accent indicator is determinate when reportProgress receives 0..1 values and falls back to pending state only when progress is unavailable.",
|
|
504
|
-
"defineToolcraft hoists panelActions into the controls panel sticky footer automatically.",
|
|
505
|
-
"Product-output apps must always include export in panelActions.",
|
|
506
|
-
'Export-labeled panelActions use icon "upload-simple", matching the Setup "Export Settings" action; do not use "download", "download-simple", or "export" icons for Export PNG or Export Video.',
|
|
507
|
-
"Static or still-output apps include Export PNG as the primary footer action.",
|
|
508
|
-
'Every app with Export PNG must expose a separate "Image Export" controls section.',
|
|
509
|
-
'The Image Export section must include "export.image.format" as a Select control with PNG and JPG choices, defaulting to "png".',
|
|
510
|
-
'The Image Export section must include "export.image.resolution" as a Select control with 2K, 4K, and 8K choices, defaulting to "4k".',
|
|
511
|
-
"Image Export format and resolution render as one compact two-column inline Select pair, matching the Video Export settings structure.",
|
|
512
|
-
"Image Export resolution controls the actual exported image long edge: 2K = 2048px, 4K = 4096px, 8K = 8192px. Pass the selected runtime value to createToolcraftPngExportCanvas resolution and prove decoded image width/height in browser acceptance.",
|
|
513
|
-
"Animated apps include Export Video as the primary footer action and Export PNG as a secondary footer action.",
|
|
514
|
-
"Any app with Export Video must enable the top Toolcraft timeline; video duration, loop, and rendered timestamps come from runtime timeline state.",
|
|
515
|
-
'Animated apps with Export Video must expose a separate "Video Export" controls section.',
|
|
516
|
-
'Animated apps with both Export PNG and Export Video must expose both "Image Export" and "Video Export"; Image Export sits immediately before Video Export.',
|
|
517
|
-
'The Video Export section must include format and resolution controls such as targets "export.video.format" and "export.video.resolution".',
|
|
518
|
-
"Use Select controls for Video Export format and resolution; do not use Segmented unless the product has a deliberately tiny fixed output menu and browser tests prove every cell keeps padding.",
|
|
519
|
-
'Place the Video Export section as the final controls section directly above sticky footer panelActions.',
|
|
520
|
-
'Video Export format defaults to "mp4"; keep "webm" available as the baseline alternate unless the prompt/reference requires another default.',
|
|
521
|
-
'Video Export resolution defaults to "current"; keep "4k" available as the high-resolution alternate.',
|
|
522
|
-
"Video Export format and resolution are a compact semantic pair and should use a two-column inline layout by default; use stacked rows only when labels or selected values do not fit without clipping.",
|
|
523
|
-
'Baseline browser video formats are "mp4" and "webm"; MOV or ProRes require an explicit custom encoder/transcoder and dedicated acceptance plus performance coverage.',
|
|
524
|
-
"Video export code must choose the actual MIME/container through MediaRecorder.isTypeSupported or an equivalent encoder capability check, then fall back safely.",
|
|
525
|
-
"Video export must use getToolcraftVideoExportSize for current and 4K dimensions. Current video export uses the current canvas/output size with even encoder-safe rounding; 4K video fits inside an encoder-safe 3840x2160 box, preserves canvas aspect ratio, and uses even pixel dimensions. Do not hand-roll 4096px long-edge video sizing.",
|
|
526
|
-
"Video export must set recording canvas dimensions before captureStream, MediaRecorder, VideoEncoder, or equivalent encoder setup, and must reject recorder/encoder errors instead of returning corrupt blobs.",
|
|
527
|
-
"Offline video export duration must be encoded from runtime timeline timestamps. Do not rely on canvas.captureStream plus MediaRecorder wall-clock recording time as the only duration mechanism for rendered-frame export.",
|
|
528
|
-
'Video resolution must control exported dimensions. Use "current" output size by default; "4K" is an export resolution target, not a hardcoded 3840x2160 canvas lock.',
|
|
529
|
-
"Video export browser coverage must load the exported blob metadata and prove video.duration matches the edited runtime timeline duration; blobSize/blobType checks alone are not enough.",
|
|
530
|
-
"Video export must report frame-based progress through reportProgress during render/encode steps. PNG export should report phase progress for render, blob, and handoff when those phases are asynchronous.",
|
|
531
|
-
'Product-output apps must expose a dedicated "Background" section directly before the first export settings section. With PNG export that first section is Image Export; with video-only export it is Video Export.',
|
|
532
|
-
"Product-output apps must pass the includeBackground runtime value to createToolcraftPngExportCanvas for PNG alpha and call shouldIncludeToolcraftPreviewBackground(state) for live preview product background.",
|
|
533
|
-
"PNG export must use createToolcraftPngExportCanvas so background transparency and selected image dimensions or retina fallback are applied consistently; turning Include off makes preview product background and PNG alpha transparent without hiding the Toolcraft canvas backing or video background.",
|
|
534
|
-
"Video export must keep product background and use getToolcraftVideoExportSize for current/4K output dimensions.",
|
|
535
|
-
"Copy PNG can be a secondary action when clipboard output is useful, but copy does not replace export.",
|
|
536
|
-
"Add Copy PNG as a secondary action only when the prompt/reference includes clipboard output or the product clearly benefits from paste/share workflows.",
|
|
537
|
-
"Footer actions must be one compact horizontal group; do not split them into stacked full-width sections.",
|
|
538
|
-
"If two footer actions are needed, render secondary/outline on the left and primary on the right.",
|
|
539
|
-
"When an odd number of footer actions renders in two columns, the final unpaired action spans the full row width.",
|
|
540
|
-
],
|
|
541
|
-
commands: ["controls.apply"],
|
|
542
|
-
stateMode: "command-only",
|
|
543
|
-
},
|
|
544
|
-
palette: {
|
|
545
|
-
...control("palette", "Palette", "standalone", "component-owned"),
|
|
546
|
-
decisionCatalog: decisionCatalog({
|
|
547
|
-
strictness: "best-fit",
|
|
548
|
-
ownsValueModel: [
|
|
549
|
-
"constrained palette choice",
|
|
550
|
-
"palette family and shade",
|
|
551
|
-
"design-token color selection",
|
|
552
|
-
"style-guide color token",
|
|
553
|
-
],
|
|
554
|
-
useWhen: [
|
|
555
|
-
"Use Palette when users choose from a constrained palette family and shade rather than a free color value.",
|
|
556
|
-
"Use Palette for token-based color choices such as brand palettes, Tailwind-like shade scales, semantic palette families, or style-guide colors.",
|
|
557
|
-
],
|
|
558
|
-
doNotReplaceWith: [
|
|
559
|
-
"Do not use Palette for arbitrary color picking.",
|
|
560
|
-
"Do not use Palette for gradients, free hex colors, text color inside FontPicker, or a color value that owns opacity.",
|
|
561
|
-
],
|
|
562
|
-
acceptableAlternatives: [
|
|
563
|
-
"Use Color for a free single color.",
|
|
564
|
-
"Use ColorOpacity when opacity belongs to the same color entity.",
|
|
565
|
-
"Use Gradient for color transitions, gradient fills, stops, type, and angle.",
|
|
566
|
-
"Use FontPicker when the color belongs to product typography.",
|
|
567
|
-
],
|
|
568
|
-
layoutConstraints: [
|
|
569
|
-
"Palette is a standalone compound control.",
|
|
570
|
-
"Palette renders content-width internal dividers only when it shares a panel section with sibling controls, with 18px vertical spacing between each divider and the control content; if it is the first control in that section, only the bottom internal divider renders; if it is the last control in that section, only the top internal divider renders; and if it is the only control in the section, only the parent section dividers render.",
|
|
571
|
-
],
|
|
572
|
-
requiredAcceptance: [
|
|
573
|
-
"Prove palette.family and palette.shade both affect product output.",
|
|
574
|
-
"Prove Palette family and shade selections update runtime state immediately, before delayed persistence/commit settles.",
|
|
575
|
-
],
|
|
576
|
-
}),
|
|
577
|
-
aiUsageRules: [
|
|
578
|
-
"Use Palette only when the product value is a constrained design-token palette choice with both family and shade.",
|
|
579
|
-
"Good Palette examples: brand palette family and shade, Tailwind-like token color, style-guide color scale, semantic palette family, or theme accent token.",
|
|
580
|
-
"Do not use Palette for arbitrary free color picking; use Color instead.",
|
|
581
|
-
"Do not use Palette when opacity belongs to the same color entity; use ColorOpacity instead.",
|
|
582
|
-
"Do not use Palette for gradients or color transitions; use Gradient instead.",
|
|
583
|
-
"Do not split typography color out to Palette when the text styling belongs to FontPicker.",
|
|
584
|
-
"Palette is a live control like Color and Slider: family and shade changes must update runtime state immediately so the next canvas interaction uses the selected token without waiting for delayed commit or persistence timers.",
|
|
585
|
-
"Palette is a compound control; acceptance must prove palette.family and palette.shade both affect the product output.",
|
|
586
|
-
"Do not accept a palette test that only changes a swatch preview without proving the renderer/export consumes the selected family and shade.",
|
|
587
|
-
],
|
|
588
|
-
},
|
|
589
|
-
vector: {
|
|
590
|
-
...control("vector", "Vector", "standalone", "component-owned"),
|
|
591
|
-
decisionCatalog: decisionCatalog({
|
|
592
|
-
strictness: "exact-owner",
|
|
593
|
-
ownsValueModel: [
|
|
594
|
-
"x/y vector",
|
|
595
|
-
"user-authored stable position",
|
|
596
|
-
"user-authored stable offset",
|
|
597
|
-
"user-authored stable direction",
|
|
598
|
-
"focus point",
|
|
599
|
-
"light vector",
|
|
600
|
-
"color balance pad",
|
|
601
|
-
],
|
|
602
|
-
useWhen: [
|
|
603
|
-
"Use Vector for paired X/Y values only when the user is meant to manually author a stable two-axis product parameter such as position, offset, direction, focus, anchor, light direction, or color-balance movement.",
|
|
604
|
-
],
|
|
605
|
-
doNotReplaceWith: [
|
|
606
|
-
"Do not replace Vector with two unrelated sliders or text inputs when direct two-axis editing is the product interaction.",
|
|
607
|
-
"Do not replace animation, keyboard input, pointer input, physics, timeline phase, velocity, or simulated pose state with Vector just because the internal value has x/y coordinates.",
|
|
608
|
-
],
|
|
609
|
-
acceptableAlternatives: [
|
|
610
|
-
"Use two numeric text fields only when exact numeric entry is the primary product requirement.",
|
|
611
|
-
"Use timeline, keyboard/pointer handlers, motion sliders, path/step controls, or renderer simulation state when movement is generated by animation or user input rather than authored as a stable panel value.",
|
|
612
|
-
],
|
|
613
|
-
layoutConstraints: [
|
|
614
|
-
"One vector renders as a square pad; multiple vectors render compact pads.",
|
|
615
|
-
],
|
|
616
|
-
requiredAcceptance: [
|
|
617
|
-
"Prove vector.x and vector.y both affect product output.",
|
|
618
|
-
],
|
|
619
|
-
}),
|
|
620
|
-
aiUsageRules: [
|
|
621
|
-
"If the controls panel contains exactly one vector control, the runtime renders the vector pad as a square.",
|
|
622
|
-
"If the controls panel contains multiple vector controls, the runtime renders compact vector pads.",
|
|
623
|
-
"Multiple vector controls should live in separate semantic sections unless they intentionally belong to the same entity with other related controls.",
|
|
624
|
-
"Use Vector only for user-authored stable two-axis product parameters. Do not expose Vector for current animation state, keyboard movement, pointer movement, physics state, timeline phase, velocity, target pose, current pose, or simulated position/direction.",
|
|
625
|
-
"Before adding a Vector control to an animated or interactive product, classify movement ownership as direct-authored, timeline-driven, keyboard/pointer-driven, or simulation-owned. Only direct-authored movement may become a visible Vector control; the other ownership modes stay in renderer/runtime interaction state and use controls such as Speed, Step, Spread, Path, Duration, or Timeline when the user needs tuning.",
|
|
626
|
-
'Use variant: "whiteBalance" for temperature/tint pads: X maps cool blue to warm amber, Y maps green to magenta.',
|
|
627
|
-
'Use variant: "colorBalance" for paired color-balance axes such as cyan/red and blue/yellow correction.',
|
|
628
|
-
'Use variant: "chromaOffset" for RGB/chromatic offset vectors where the X/Y movement controls channel separation.',
|
|
629
|
-
'Use variant: "toneBias" for split-tone, duotone, or color-grading vectors where both axes describe tone or hue bias.',
|
|
630
|
-
'Use the default vector variant for spatial values such as position, offset, direction, focus, anchor, and light direction.',
|
|
631
|
-
'Default spatial vector pads use coordinateMode: "screen": dragging left/up makes vector.x and vector.y smaller so canvas objects move left/up without renderer-side Y inversion.',
|
|
632
|
-
"Vector pad value labels render compact rounded coordinates. Do not expose raw floating-point strings such as -0.07070312499999998 in the controls panel.",
|
|
633
|
-
"Double-clicking a vector pad resets both axes to the control default through the normal runtime value update, matching section header reset semantics; if no default is defined, the fallback is 0,0. Do not add a separate custom reset UI for this basic pad reset behavior.",
|
|
634
|
-
"Holding Shift while dragging a vector pad locks movement to the dominant axis and must not select text or page content; do not build a custom pad just to support axis-constrained movement.",
|
|
635
|
-
'Use coordinateMode: "cartesian" only when the product intentionally exposes mathematical Y-up coordinates instead of canvas/screen movement.',
|
|
636
|
-
"Do not add custom vector sizing props in generated schemas; choose the number, variant, and section grouping from product need and let the runtime size the pads.",
|
|
637
|
-
"Vector is a compound control; acceptance must prove vector.x and vector.y both affect the product output and that the vector represents a user-authored stable two-axis parameter rather than current animation, input, or simulation state.",
|
|
638
|
-
],
|
|
639
|
-
},
|
|
640
|
-
color: {
|
|
641
|
-
...control("color", "Color", "standalone", "component-owned"),
|
|
642
|
-
decisionCatalog: decisionCatalog({
|
|
643
|
-
strictness: "best-fit",
|
|
644
|
-
ownsValueModel: [
|
|
645
|
-
"single free color",
|
|
646
|
-
"hex color value",
|
|
647
|
-
"role color",
|
|
648
|
-
],
|
|
649
|
-
useWhen: [
|
|
650
|
-
"Use Color for one editable free color without opacity or gradient stops.",
|
|
651
|
-
],
|
|
652
|
-
doNotReplaceWith: [
|
|
653
|
-
"Do not use multiple Color controls as a substitute for an adjustable Gradient.",
|
|
654
|
-
"Do not pair Color with a separate opacity control when ColorOpacity fits.",
|
|
655
|
-
],
|
|
656
|
-
acceptableAlternatives: [
|
|
657
|
-
"Use ColorOpacity when opacity belongs to the color entity.",
|
|
658
|
-
"Use Gradient for color transitions, fills with stops, or angle/type editing.",
|
|
659
|
-
"Use Palette for constrained design-token choices.",
|
|
660
|
-
],
|
|
661
|
-
layoutConstraints: [
|
|
662
|
-
"Plain Color controls may render two per row only when no opacity is present.",
|
|
663
|
-
"Odd trailing plain Color controls in a multi-color bank keep the same half-width footprint as paired colors.",
|
|
664
|
-
"Color label visibility depends on user usefulness: palette variation banks omit per-item labels; distinct color roles keep labels.",
|
|
665
|
-
],
|
|
666
|
-
requiredAcceptance: [
|
|
667
|
-
"Prove the selected color affects product output, preview, or export.",
|
|
668
|
-
],
|
|
669
|
-
}),
|
|
670
|
-
aiUsageRules: [
|
|
671
|
-
"Color controls can be standalone color sections or grouped fields inside a semantic control section.",
|
|
672
|
-
"First identify the semantic entity the color belongs to, such as Square 1, Square 2, Background, Object, Connector, Glow, Tone Mapping, Brand, or Export.",
|
|
673
|
-
"Keep a color inside a section when it configures the same entity as nearby controls. Example: Square 1 (Right) contains Connections, Hover radius, and Color in one section.",
|
|
674
|
-
"Use a standalone color section only when the color itself is the whole semantic section; the section title must describe the product role such as Background, Object, Connector, Accent, Gradient, or Brand.",
|
|
675
|
-
"When color belongs to the same object or effect as nearby controls, keep it inside that section and use a concise field label that is unambiguous in context, such as Color in a Square section or Symbol color in a mixed Style section.",
|
|
676
|
-
"Decide color label visibility from the user's point of view. Omit labels for color banks that only add palette variety, such as Accent Shades, Bead Colors, or palette.accent1..5.",
|
|
677
|
-
"Make color label visibility a group-level decision: do not mix labeled and unlabeled items inside one semantic color bank.",
|
|
678
|
-
"Keep visible labels when colors edit distinct user-facing entities or roles, such as Fill, Stroke, Background, Connector, Object, or Highlight.",
|
|
679
|
-
"A color bank can share a section with distribution controls such as Spread, Mix, or Randomness and still keep each color item unlabeled when the section title names the palette context.",
|
|
680
|
-
"The standalone default applies only to color-only sections; mixed semantic sections keep color grouped with nearby controls.",
|
|
681
|
-
"Never use generic Color or Colors as a generated section title. If no meaningful color role exists and the colors are just basic colors, use a neutral section title such as Appearance instead of omitting the title.",
|
|
682
|
-
"Do not split a grouped object section into a separate generated Color section; if the color role is unclear, ask the user before implementation.",
|
|
683
|
-
"When one short numeric/text field and one Color field configure the same entity, keep them in one two-column inline layout group.",
|
|
684
|
-
'Mixed inline rows usually require visible labels on both controls. Toggle-plus-parameter rows are the section-owned exception: keep the Switch/Checkbox label visible and set the non-toggle parameter label to false; if the parameter label is needed, stack the controls instead. All 50/50 inline rows use the same horizontal column gap as paired Select controls. The required Background row uses the Switch label "Include" and sets the background Color control label to false. Palette variation color banks are the other exception when the group/section label already names the color bank.',
|
|
685
|
-
"Plain Color popovers must not show opacity controls. If opacity is editable, use ColorOpacity instead.",
|
|
686
|
-
"Product-output apps always expose renderer-owned output background color as a schema color target such as appearance.background or scene.background.",
|
|
687
|
-
'Pair renderer-owned output background color with export.includeBackground in one Background section directly before export settings. Use an equal-width inline row with the export.includeBackground Switch labeled "Include" on the left and the background Color parameter with label false on the right; each control occupies one half of the row.',
|
|
688
|
-
"Preview, PNG export, and video export must read the runtime background color value instead of hardcoding that background in CSS, Canvas fillStyle, or WebGL clearColor. export.includeBackground controls live preview product background and PNG alpha; it must not make the Toolcraft canvas shell/backing or video output transparent.",
|
|
689
|
-
"Render multiple related color fields in one section with at most two colors per row.",
|
|
690
|
-
"If a multi-color bank has an odd trailing plain Color, keep that last Color at half width; only ColorOpacity or intentionally full-width compound controls occupy a full row.",
|
|
691
|
-
],
|
|
692
|
-
},
|
|
693
|
-
gradient: {
|
|
694
|
-
...control("gradient", "Gradient", "standalone", "component-owned"),
|
|
695
|
-
decisionCatalog: decisionCatalog({
|
|
696
|
-
strictness: "exact-owner",
|
|
697
|
-
ownsValueModel: [
|
|
698
|
-
"gradient fill",
|
|
699
|
-
"gradient type",
|
|
700
|
-
"gradient angle",
|
|
701
|
-
"gradient stops",
|
|
702
|
-
"stop colors",
|
|
703
|
-
"stop opacity",
|
|
704
|
-
"stop positions",
|
|
705
|
-
],
|
|
706
|
-
useWhen: [
|
|
707
|
-
"Use Gradient when the product needs an adjustable gradient, color transition, multi-stop fill, linear fill, radial fill, angular fill, or diamond fill.",
|
|
708
|
-
"Use Gradient when the prompt or reference mentions gradient stops, gradient angle, gradient type, or editable color transition.",
|
|
709
|
-
],
|
|
710
|
-
doNotReplaceWith: [
|
|
711
|
-
"Do not replace Gradient with two Color controls.",
|
|
712
|
-
"Do not replace Gradient with ColorOpacity plus sliders.",
|
|
713
|
-
"Do not build custom gradient UI unless the built-in Gradient cannot express the interaction and the custom escape hatch is documented.",
|
|
714
|
-
],
|
|
715
|
-
acceptableAlternatives: [
|
|
716
|
-
"Use Color or ColorOpacity only when the product explicitly needs fixed single colors, not an adjustable gradient.",
|
|
717
|
-
],
|
|
718
|
-
layoutConstraints: [
|
|
719
|
-
"Gradient is a full standalone compound control.",
|
|
720
|
-
"Gradient renders content-width internal dividers only when it shares a panel section with sibling controls, with 18px vertical spacing between each divider and the control content; if it is the first control in that section, only the bottom internal divider renders; if it is the last control in that section, only the top internal divider renders; and if it is the only control in the section, only the parent section dividers render.",
|
|
721
|
-
],
|
|
722
|
-
requiredAcceptance: [
|
|
723
|
-
"Prove gradientType, angle, stop position, stop color, and stop opacity affect product output or export output.",
|
|
724
|
-
],
|
|
725
|
-
}),
|
|
726
|
-
aiUsageRules: [
|
|
727
|
-
"Gradient is a compound control; acceptance must prove gradient.gradientType, gradient.angle, gradient.stops.position, gradient.stops.color, and gradient.stops.opacity all affect the product output when visible.",
|
|
728
|
-
"Keep Gradient type/angle, draggable stop track, and Stops list inside the built-in Gradient control. The full Gradient control is visually separated with content-width dividers only when it shares a section with sibling controls; do not put dividers only around the Stops list and do not rebuild it as separate schema controls.",
|
|
729
|
-
"Do not accept a gradient test that edits only a stop color; Linear/Radial/Angular/Diamond selection, angle, stop position, stop color, and stop opacity must be wired or the control should be simplified.",
|
|
730
|
-
"If the renderer intentionally supports only a subset of gradient behavior, do not use the full Gradient control; use simpler controls that match the renderer behavior.",
|
|
731
|
-
],
|
|
732
|
-
},
|
|
733
|
-
fontPicker: {
|
|
734
|
-
...control("fontPicker", "FontPicker", "standalone", "component-owned"),
|
|
735
|
-
decisionCatalog: decisionCatalog({
|
|
736
|
-
strictness: "exact-owner",
|
|
737
|
-
ownsValueModel: [
|
|
738
|
-
"font family",
|
|
739
|
-
"font preview",
|
|
740
|
-
"font weight",
|
|
741
|
-
"font size",
|
|
742
|
-
"text case",
|
|
743
|
-
"letter spacing",
|
|
744
|
-
"line height",
|
|
745
|
-
"text color",
|
|
746
|
-
"text opacity",
|
|
747
|
-
],
|
|
748
|
-
useWhen: [
|
|
749
|
-
"Use FontPicker when product typography needs font family, weight, size, case, letter spacing, line height, text color, or text opacity.",
|
|
750
|
-
],
|
|
751
|
-
doNotReplaceWith: [
|
|
752
|
-
"Do not replace FontPicker with a plain Select plus separate typography controls.",
|
|
753
|
-
"Do not build a custom font popup for product typography.",
|
|
754
|
-
"Do not add sibling controls for text color, text opacity, case, weight, size, letter spacing, or line height when they belong to the same typography entity.",
|
|
755
|
-
],
|
|
756
|
-
acceptableAlternatives: [
|
|
757
|
-
"Use TextInput or Select only for non-typographic labels or finite text choices.",
|
|
758
|
-
],
|
|
759
|
-
layoutConstraints: [
|
|
760
|
-
"FontPicker owns its popup and internal footer controls.",
|
|
761
|
-
"FontPicker renders content-width internal dividers only when it shares a panel section with sibling controls, with 18px vertical spacing between each divider and the control content; if it is the first control in that section, only the bottom internal divider renders; if it is the last control in that section, only the top internal divider renders; and if it is the only control in the section, only the parent section dividers render.",
|
|
762
|
-
],
|
|
763
|
-
requiredAcceptance: [
|
|
764
|
-
"Prove fontId, fontWeight, fontSize, letterSpacing, lineHeight, textCase, color, and opacity affect actual product text output.",
|
|
765
|
-
],
|
|
766
|
-
}),
|
|
767
|
-
aiUsageRules: [
|
|
768
|
-
"FontPicker owns the font preview select, virtualized font popup, category filters, search, preview loading, font-weight select, font-size input, text-case select, text color/opacity control, letter-spacing slider, and line-height slider.",
|
|
769
|
-
"Do not recreate FontPicker with a plain Select plus separate sliders; use type: \"fontPicker\" so the popup mechanics and footer controls stay intact.",
|
|
770
|
-
"Use one object value with fontId, fontWeight, fontSize, letterSpacing, lineHeight, textCase, color, and opacity. Keep typography renderers wired to all eight parts.",
|
|
771
|
-
"FontPicker standard/default text color is #FFFFFF with opacity 100; omit color/opacity or use those values unless the prompt or reference explicitly requires a different initial text color.",
|
|
772
|
-
"Any product text controlled by FontPicker must render fontId, fontWeight, fontSize, letterSpacing, lineHeight, textCase, color, and opacity in preview and export; do not leave typography values as panel-only runtime state.",
|
|
773
|
-
"FontPicker is an atomic compound typography control. Do not split any owned typography part into a neighboring schema control for the same product text entity.",
|
|
774
|
-
"Do not put a help tooltip on FontPicker just to list its owned fields. If the section title and FontPicker labels already make the text target clear, omit description.",
|
|
775
|
-
"FontPicker is a compound control; acceptance must prove fontPicker.fontId, fontPicker.fontWeight, fontPicker.fontSize, fontPicker.letterSpacing, fontPicker.lineHeight, fontPicker.textCase, fontPicker.color, and fontPicker.opacity all affect the product output.",
|
|
776
|
-
"FontPicker acceptance must inspect the actual product text output after changing font, weight, size, letter spacing, line height, text case, color, and opacity; runtime state, select labels, or popup preview text alone are not enough.",
|
|
777
|
-
"Browser verification must open the popup, choose a different font, change font weight, change font size, change text case, change text color/opacity, move the letter-spacing footer slider, and move the line-height footer slider.",
|
|
778
|
-
],
|
|
779
|
-
},
|
|
780
|
-
curves: {
|
|
781
|
-
...control("curves", "Curves", "standalone", "component-owned"),
|
|
782
|
-
decisionCatalog: decisionCatalog({
|
|
783
|
-
strictness: "exact-owner",
|
|
784
|
-
ownsValueModel: [
|
|
785
|
-
"editable curve",
|
|
786
|
-
"tone curve",
|
|
787
|
-
"response curve",
|
|
788
|
-
"easing curve",
|
|
789
|
-
"remapping curve",
|
|
790
|
-
"channel curve",
|
|
791
|
-
],
|
|
792
|
-
useWhen: [
|
|
793
|
-
"Use Curves for editable remapping, tone, response, easing, opacity, depth, mask, or channel curves.",
|
|
794
|
-
],
|
|
795
|
-
doNotReplaceWith: [
|
|
796
|
-
"Do not replace Curves with generic sliders when the product needs an editable curve.",
|
|
797
|
-
"Do not build custom curve UI just to remove RGB tabs; use variant single.",
|
|
798
|
-
],
|
|
799
|
-
acceptableAlternatives: [
|
|
800
|
-
"Use Slider only when the product needs one scalar strength value, not a curve shape.",
|
|
801
|
-
],
|
|
802
|
-
layoutConstraints: [
|
|
803
|
-
"Use variant single for one standalone curve and RGB variant only for color-correction or channel-specific curves.",
|
|
804
|
-
"Single Curves is one labeled control and does not render internal dividers, even inside mixed sections.",
|
|
805
|
-
"RGB Curves is a compound channel control and renders content-width internal dividers only when it shares a panel section with sibling controls, with 18px vertical spacing between each rendered divider and the control content; if it is the first control in that section, only the bottom internal divider renders and the top internal padding is removed; if it is the last control in that section, only the top internal divider renders and the bottom internal padding is removed; and if it is the only control in the section, only the parent section dividers render.",
|
|
806
|
-
],
|
|
807
|
-
requiredAcceptance: [
|
|
808
|
-
"Prove curves.points affect product output; RGB curves also prove activeChannel affects output.",
|
|
809
|
-
],
|
|
810
|
-
}),
|
|
811
|
-
aiUsageRules: [
|
|
812
|
-
'Use Curves for editable remapping curves. RGB/R/G/B tabs are only for color-correction or channel-specific curves; use variant: "single" for one standalone curve without channel tabs.',
|
|
813
|
-
'Use variant: "single" for a single acceleration, bend, easing, opacity, response, depth, mask, threshold, tone-response, or mapping curve. Do not create a custom curve UI just to remove RGB tabs.',
|
|
814
|
-
"RGB Curves is a color-correction-specific case; do not force RGB/R/G/B tabs onto products that need only one response, bend, depth, or easing curve.",
|
|
815
|
-
'Use interpolation: "smooth" for photo/editor-like visual tone, color, and RGB curves where the curve should feel like a creative editor spline.',
|
|
816
|
-
'Use interpolation: "monotone" for depth, response, mask, opacity, threshold, and data-mapping curves where order must be preserved and overshoot is unsafe. Single curves default to monotone unless smooth is explicitly requested.',
|
|
817
|
-
"Single Curves is one labeled control without internal dividers; RGB Curves is the compound variant with channel tabs and section dividers when mixed with sibling controls.",
|
|
818
|
-
"RGB curves acceptance must prove curves.activeChannel and curves.points both affect the product output. Single curves acceptance proves curves.points.",
|
|
819
|
-
"Curves acceptance should include an off-center control point near an edge so smooth-vs-monotone interpolation mistakes are visible in product output.",
|
|
820
|
-
"Do not accept a curves test that only opens the UI or changes selected point state without proving renderer/export output changes.",
|
|
821
|
-
],
|
|
822
|
-
},
|
|
823
|
-
anchorGrid: {
|
|
824
|
-
...control("anchorGrid", "AnchorGrid", "standalone", "component-owned"),
|
|
825
|
-
decisionCatalog: decisionCatalog({
|
|
826
|
-
strictness: "best-fit",
|
|
827
|
-
ownsValueModel: [
|
|
828
|
-
"anchor position",
|
|
829
|
-
"edge or corner placement",
|
|
830
|
-
"nine-point alignment",
|
|
831
|
-
],
|
|
832
|
-
useWhen: [
|
|
833
|
-
"Use AnchorGrid for choosing an anchor, alignment point, or edge/corner placement.",
|
|
834
|
-
],
|
|
835
|
-
doNotReplaceWith: [
|
|
836
|
-
"Do not use AnchorGrid for freeform two-axis movement; use Vector.",
|
|
837
|
-
],
|
|
838
|
-
acceptableAlternatives: [
|
|
839
|
-
"Use Vector only for stable direct-authored continuous position or direction parameters.",
|
|
840
|
-
],
|
|
841
|
-
layoutConstraints: [
|
|
842
|
-
"AnchorGrid is a standalone position selector.",
|
|
843
|
-
],
|
|
844
|
-
requiredAcceptance: [
|
|
845
|
-
"Prove selected anchor changes product placement.",
|
|
846
|
-
],
|
|
847
|
-
}),
|
|
848
|
-
aiUsageRules: [
|
|
849
|
-
"AnchorGrid is a position selector; acceptance must prove anchorGrid.position changes product placement, not only selected button state.",
|
|
850
|
-
"Choose representative edge/corner anchors in browser tests so center-only behavior cannot pass.",
|
|
851
|
-
],
|
|
852
|
-
},
|
|
853
|
-
channelMixer: {
|
|
854
|
-
...control("channelMixer", "ChannelMixer", "standalone", "component-owned"),
|
|
855
|
-
decisionCatalog: decisionCatalog({
|
|
856
|
-
strictness: "exact-owner",
|
|
857
|
-
ownsValueModel: [
|
|
858
|
-
"RGB channel mixer",
|
|
859
|
-
"RGB channel matrix",
|
|
860
|
-
"active RGB output channel and RGB source-channel values",
|
|
861
|
-
],
|
|
862
|
-
useWhen: [
|
|
863
|
-
"Use ChannelMixer only when product behavior edits RGB channel mixing, channel swapping, or an RGB channel matrix.",
|
|
864
|
-
],
|
|
865
|
-
doNotReplaceWith: [
|
|
866
|
-
"Do not replace ChannelMixer with disconnected sliders for each channel when the active channel matrix matters.",
|
|
867
|
-
"Do not use ChannelMixer for arbitrary non-RGB channels, data channels, audio bands, masks, layers, or option groups.",
|
|
868
|
-
],
|
|
869
|
-
acceptableAlternatives: [
|
|
870
|
-
"Use Color or Curves for simple color choice or tone curves that are not channel matrix mixing.",
|
|
871
|
-
"Use Select, Segmented, Slider, Curves, or a justified custom control for non-RGB channel-like product domains.",
|
|
872
|
-
],
|
|
873
|
-
layoutConstraints: [
|
|
874
|
-
"ChannelMixer is a standalone compound control.",
|
|
875
|
-
"ChannelMixer renders content-width internal dividers only when it shares a panel section with sibling controls, with 18px vertical spacing between each divider and the control content; if it is the first control in that section, only the bottom internal divider renders; if it is the last control in that section, only the top internal divider renders; and if it is the only control in the section, only the parent section dividers render.",
|
|
876
|
-
],
|
|
877
|
-
requiredAcceptance: [
|
|
878
|
-
"Prove channelMixer.activeChannel and channelMixer.values both affect product output.",
|
|
879
|
-
],
|
|
880
|
-
}),
|
|
881
|
-
aiUsageRules: [
|
|
882
|
-
"ChannelMixer is RGB-specific: it renders R/G/B tabs and Red, Green, Blue sliders for an RGB channel matrix.",
|
|
883
|
-
"Use ChannelMixer only for RGB channel mixing, channel swapping, or color-correction matrix behavior; do not use it for arbitrary channel lists.",
|
|
884
|
-
"ChannelMixer is a compound control; acceptance must prove channelMixer.activeChannel and channelMixer.values both affect the product output.",
|
|
885
|
-
"Do not accept a channel mixer test that changes only the active tab or only one slider without proving the selected channel matrix is consumed by the renderer/export.",
|
|
886
|
-
],
|
|
887
|
-
},
|
|
888
|
-
fileDrop: {
|
|
889
|
-
...control("fileDrop", "FileDrop", "standalone", "component-owned"),
|
|
890
|
-
decisionCatalog: decisionCatalog({
|
|
891
|
-
strictness: "exact-owner",
|
|
892
|
-
ownsValueModel: [
|
|
893
|
-
"source material upload",
|
|
894
|
-
"file import",
|
|
895
|
-
"media import",
|
|
896
|
-
"drop target",
|
|
897
|
-
],
|
|
898
|
-
useWhen: [
|
|
899
|
-
"Use FileDrop for source material uploads, file import, or drag-and-drop media input.",
|
|
900
|
-
],
|
|
901
|
-
doNotReplaceWith: [
|
|
902
|
-
"Do not place upload UI on the canvas.",
|
|
903
|
-
"Do not draw a custom canvas empty-state design, CTA, fake sample output, decorative placeholder, or agent-invented preset source while waiting for uploaded content.",
|
|
904
|
-
"Do not build custom file buttons for source media import.",
|
|
905
|
-
],
|
|
906
|
-
acceptableAlternatives: [
|
|
907
|
-
"Use ImagePicker when users choose from built-in visual options rather than uploading a file.",
|
|
908
|
-
],
|
|
909
|
-
layoutConstraints: [
|
|
910
|
-
"FileDrop lives in the controls panel; single-layer apps use its preview and clear behavior.",
|
|
911
|
-
"When fileDrop has assetKind: image and one image is present, the runtime renders image transform actions through the built-in actions-control directly below the uploader: 90° Right, Flip horizontal, and Flip vertical.",
|
|
912
|
-
"FileDrop image previews keep a stable preview frame when rotated or flipped. Rotated preview bitmaps use contain semantics inside that frame so the controls-panel preview never crops the image; canvas/product renderers may still use cover/crop when the uploaded image is source material.",
|
|
913
|
-
"When fileDrop has multiple: true and more than one image is present, the runtime renders a sortable four-column thumbnail grid with the add-more tile last.",
|
|
914
|
-
"When fileDrop has multiple: true and more than one image is present, image transform actions render only after the user selects a thumbnail, and they target only that selected image.",
|
|
915
|
-
"When fileDrop has assetKind: file, the runtime renders a sortable file list with a paperclip icon, filename, remove button, and row separators using --border/5.",
|
|
916
|
-
],
|
|
917
|
-
requiredAcceptance: [
|
|
918
|
-
"Prove file import changes media state and product output; prove clear, reorder, rotate, flip, and section/global reset update source material.",
|
|
919
|
-
],
|
|
920
|
-
}),
|
|
921
|
-
aiUsageRules: [
|
|
922
|
-
"Use fileDrop for source material uploads in the controls panel, not on the canvas.",
|
|
923
|
-
'Use fileDrop with assetKind: "image" for image-only source media and assetKind: "file" for arbitrary uploaded files.',
|
|
924
|
-
"If an app ships with predefined source files or background images, declare them as schema media.defaultAssets with sourceTarget matching the fileDrop control. They must render as ordinary attached files in fileDrop, not as hidden renderer constants or canvas placeholder artwork.",
|
|
925
|
-
"Predefined media files are default runtime state: users can remove them to get an empty source/canvas state, persistence may keep that removal with include: [\"media\"], and global or section Reset restores the default attached files.",
|
|
926
|
-
"When uploaded/imported content is part of the source-material flow, the canvas must not show agent-invented artwork, CTA text, fake sample output, decorative placeholders, or preset source designs before real content exists; keep the canvas neutral/runtime-backed and put upload affordance in fileDrop.",
|
|
927
|
-
"Do not add procedural Source Preset modes only to avoid an empty canvas. A default procedural or reference source is allowed only when the prompt/reference explicitly defines it and the worklog records that evidence.",
|
|
928
|
-
"In single-layer apps, the runtime shows the uploaded image as the fileDrop preview and provides the clear action.",
|
|
929
|
-
"In image mode, the runtime owns image transform actions: 90° Right, Flip horizontal, and Flip vertical. These actions render through the built-in actions-control in one three-column row with compact visible labels: 90°, Flip H, Flip V; keep a 6px vertical gap between the uploader and action row. Do not create a custom image action button grid. They update runtime mediaAssets transform metadata, and product preview/export must consume that metadata instead of keeping a separate transform state.",
|
|
930
|
-
"FileDrop panel previews are not product canvas rendering. Keep the preview frame height stable across image rotation/flip, and contain the rotated bitmap inside that frame so horizontal or vertical uploads are not cropped by the control.",
|
|
931
|
-
"When exactly one uploaded image is present, image transform actions are visible immediately. When multiple images are present, users select a thumbnail first; no transform actions render until a thumbnail is selected, and the action applies only to that selected image.",
|
|
932
|
-
"In file mode, the runtime shows uploaded files as a sortable list with paperclip icons, file names, remove buttons, and --border/5 separators.",
|
|
933
|
-
"In single-layer apps, global Reset controls and section reset must restore fileDrop source media to schema media.defaultAssets for that target; when no default asset exists, Reset removes uploaded media and returns the fileDrop target to defaultValue.",
|
|
934
|
-
"Use fileDrop with multiple: true when the app needs several uploaded images as one source set; do not build a custom thumbnail uploader for this.",
|
|
935
|
-
"When multiple uploaded images are present, the runtime appends media, shows a sortable four-column preview grid, puts the add-more tile last, and exposes per-image removal.",
|
|
936
|
-
"Canvas drops route to the first visible matching fileDrop target by asset kind: image files prefer image uploaders, non-image files prefer file uploaders, and file uploaders accept images only when no image uploader matches.",
|
|
937
|
-
"Dragging thumbnails reorders runtime mediaAssets; preview, export, and renderer mapping must consume that media order instead of maintaining a separate product-only order.",
|
|
938
|
-
"When uploaded images are used as canvas/background source material, draw them with cover/crop behavior: scale proportionally until the current canvas bounds are fully covered, keep the canvas size/settings unchanged, and crop overflow at the canvas bounds.",
|
|
939
|
-
"Do not create custom upload buttons, file lists, or file sorting for generic source uploads when fileDrop can represent the source set.",
|
|
940
|
-
"In multi-layer apps, deletion and visibility belong to the Layers panel; fileDrop remains an upload target.",
|
|
941
|
-
],
|
|
942
|
-
commands: ["media.delete", "media.import", "media.reorder", "media.transform"],
|
|
943
|
-
},
|
|
944
|
-
imagePicker: {
|
|
945
|
-
...control("imagePicker", "ImagePicker", "standalone", "component-owned"),
|
|
946
|
-
decisionCatalog: decisionCatalog({
|
|
947
|
-
strictness: "exact-owner",
|
|
948
|
-
ownsValueModel: [
|
|
949
|
-
"visual option choice",
|
|
950
|
-
"thumbnail selection",
|
|
951
|
-
"preset image choice",
|
|
952
|
-
],
|
|
953
|
-
useWhen: [
|
|
954
|
-
"Use ImagePicker when users choose one visual option from a set of thumbnails or images.",
|
|
955
|
-
],
|
|
956
|
-
doNotReplaceWith: [
|
|
957
|
-
"Do not recreate ImagePicker grids manually.",
|
|
958
|
-
"Do not show choices that the renderer treats as fallback or no-op.",
|
|
959
|
-
],
|
|
960
|
-
acceptableAlternatives: [
|
|
961
|
-
"Use Select for non-visual named options.",
|
|
962
|
-
"Use FileDrop for user-uploaded source material.",
|
|
963
|
-
],
|
|
964
|
-
layoutConstraints: [
|
|
965
|
-
"Runtime owns tile sizing by option count.",
|
|
966
|
-
],
|
|
967
|
-
requiredAcceptance: [
|
|
968
|
-
"Prove each visible image choice changes product output or selected visual data.",
|
|
969
|
-
],
|
|
970
|
-
}),
|
|
971
|
-
aiUsageRules: [
|
|
972
|
-
"ImagePicker owns thumbnail layout; pass the item list only and do not recreate the grid manually.",
|
|
973
|
-
"Every visible ImagePicker item must be actionable in the current product context.",
|
|
974
|
-
"Do not show selectable image choices that the renderer later sanitizes to a fallback or no-op.",
|
|
975
|
-
"If available choices depend on another control such as template, mode, or selected object, either make every visible item valid for every mode, split the choice into separate semantic controls, or ask the user before implementation.",
|
|
976
|
-
"A defensive invalid-value fallback is allowed, but it is not acceptance proof for a visible ImagePicker option.",
|
|
977
|
-
"Tests must choose each visible ImagePicker item and assert the selected image, texture, gradient, or exported pixels change in the product output.",
|
|
978
|
-
"Do not accept renderer data attributes, runtime target changes, or option existence as final proof that an image choice works.",
|
|
979
|
-
],
|
|
980
|
-
},
|
|
981
|
-
code: {
|
|
982
|
-
...control("code", "CodeTextarea", "standalone", "required"),
|
|
983
|
-
decisionCatalog: decisionCatalog({
|
|
984
|
-
strictness: "best-fit",
|
|
985
|
-
ownsValueModel: [
|
|
986
|
-
"long text",
|
|
987
|
-
"multiline content",
|
|
988
|
-
"structured text",
|
|
989
|
-
"prompt",
|
|
990
|
-
"JSON",
|
|
991
|
-
"CSS",
|
|
992
|
-
"shader code",
|
|
993
|
-
],
|
|
994
|
-
useWhen: [
|
|
995
|
-
"Use CodeTextarea for potentially long, multiline, or structured text values.",
|
|
996
|
-
],
|
|
997
|
-
doNotReplaceWith: [
|
|
998
|
-
"Do not use repeated TextInput controls for one long content value.",
|
|
999
|
-
],
|
|
1000
|
-
acceptableAlternatives: [
|
|
1001
|
-
"Use TextInput for short single-line values.",
|
|
1002
|
-
],
|
|
1003
|
-
layoutConstraints: [
|
|
1004
|
-
"CodeTextarea is capped at 12 visible lines and scrolls internally.",
|
|
1005
|
-
],
|
|
1006
|
-
requiredAcceptance: [
|
|
1007
|
-
"Prove long text edits affect product content while typing.",
|
|
1008
|
-
],
|
|
1009
|
-
}),
|
|
1010
|
-
aiUsageRules: [
|
|
1011
|
-
"CodeTextarea is the multiline text input for any potentially long value, not only source code.",
|
|
1012
|
-
"Do not use CodeTextarea for short single-line canvas text, button labels, names, titles, captions, badges, or short tokens; use TextInput.",
|
|
1013
|
-
"Use text for short single-line strings such as names, button labels, small numeric values, compact prompts, titles, captions, and short tokens.",
|
|
1014
|
-
"Use code only when the user may enter long prompts, multiline text, instructions, JSON, CSS, shader code, scripts, templates, or other long structured data.",
|
|
1015
|
-
"If CodeTextarea has a short single-line default value, the schema description must make the long, multiline, or structured-content reason explicit.",
|
|
1016
|
-
"CodeTextarea is a content editor and applies values while typing; do not wait for blur, Enter, or Cmd/Ctrl+Enter to update runtime state.",
|
|
1017
|
-
"CodeTextarea height is capped at 12 visible text lines; long content scrolls inside the textarea instead of making the controls panel taller.",
|
|
1018
|
-
"Do not name a section Code unless the product value is actually code; use the product role such as Prompt, Instructions, Template, JSON, Shader, or CSS.",
|
|
1019
|
-
],
|
|
1020
|
-
},
|
|
1021
|
-
customControl: {
|
|
1022
|
-
decisionCatalog: decisionCatalog({
|
|
1023
|
-
strictness: "custom-escape-hatch",
|
|
1024
|
-
ownsValueModel: [
|
|
1025
|
-
"product-specific interaction not expressible by built-in controls",
|
|
1026
|
-
],
|
|
1027
|
-
useWhen: [
|
|
1028
|
-
"Use custom controls only after checking all relevant built-ins and documenting why the closest built-in is insufficient.",
|
|
1029
|
-
],
|
|
1030
|
-
doNotReplaceWith: [
|
|
1031
|
-
"Do not use custom controls to recreate built-in controls, runtime panels, toolbar, timeline, layers, canvas, or sticky panel actions.",
|
|
1032
|
-
],
|
|
1033
|
-
acceptableAlternatives: [
|
|
1034
|
-
"Prefer built-in schema controls plus renderer logic whenever the value model fits an existing control.",
|
|
1035
|
-
],
|
|
1036
|
-
layoutConstraints: [
|
|
1037
|
-
"Custom UI must use Toolcraft primitives and minimal product-specific chrome.",
|
|
1038
|
-
],
|
|
1039
|
-
requiredAcceptance: [
|
|
1040
|
-
"Document rejected built-ins, prove runtime-state writes, and prove product output or command side effects.",
|
|
1041
|
-
],
|
|
1042
|
-
}),
|
|
1043
|
-
aiUsageRules: [
|
|
1044
|
-
"Use custom controls only for product interactions that built-in controls cannot express.",
|
|
1045
|
-
"Do not use a custom control to recreate a built-in Slider, RangeSlider, Select, Segmented, Switch, Checkbox, Color, ColorOpacity, Gradient, FontPicker, ImagePicker, FileDrop, TextInput, CodeTextarea, RangeInput, Palette, Actions, CollectionActions, Curves, AnchorGrid, ChannelMixer, Vector, or PanelActions control.",
|
|
1046
|
-
"When a custom control owns a growable, removable, selectable, or reorderable runtime item set, its builtInFitCheck must explicitly check collectionActions and actions before choosing custom; this is based on the value model and user workflow, not on entity names such as masks or glyphs.",
|
|
1047
|
-
"Do not justify custom controls with icons, layout, styling, compactness, or custom buttons alone. The fit check must name the product interaction or value model that built-ins cannot express.",
|
|
1048
|
-
"Custom controls may use Toolcraft primitives for small app-specific chrome, but must not import or render low-level runtime surfaces or duplicate toolbar, timeline, layers, canvas, panel, or built-in control mechanics.",
|
|
1049
|
-
"Custom controls must render the minimum UI needed to understand the value, context, and available actions; avoid decorative metadata and text that repeats what the section, label, or visible item already explains.",
|
|
1050
|
-
"Every visible custom-control element must justify its space by enabling selection, ordering, preview, removal, upload, editing, or status that affects the product.",
|
|
1051
|
-
"Use Toolcraft primitives and tokens for all custom-control chrome; do not hand-style basic buttons, inputs, selects, sliders, scroll areas, or focus states.",
|
|
1052
|
-
"Custom-control action buttons must be sized for the interaction. Do not shrink destructive, reorder, upload, or primary actions below comfortable kit button/icon-button sizes just to fit more text.",
|
|
1053
|
-
"Choose preview sizes that match the product object scale. A glyph, swatch, chip, or thumbnail can be compact, but its actions and hit targets must stay readable and clickable.",
|
|
1054
|
-
"If a custom item needs explanatory context, prefer concise labels such as Darkest, Mid tone, or Lightest; omit file names, long captions, and duplicated helper text unless they are required to distinguish items.",
|
|
1055
|
-
"Acceptance and browser tests must prove custom-control interactions work through runtime state and product output, not only that custom markup rendered.",
|
|
1056
|
-
],
|
|
1057
|
-
capabilities: ["controlRenderers", "runtime-state", "minimal-ui"],
|
|
1058
|
-
commands: [],
|
|
1059
|
-
historyPolicy: "patch",
|
|
1060
|
-
id: "customControl",
|
|
1061
|
-
kind: "control",
|
|
1062
|
-
labelPolicy: "required",
|
|
1063
|
-
schemaType: "controlRenderers",
|
|
1064
|
-
stateMode: "controlled",
|
|
1065
|
-
visualComponent: "CustomControlRenderer",
|
|
1066
|
-
},
|
|
1067
|
-
canvas: {
|
|
1068
|
-
aiUsageRules: [
|
|
1069
|
-
"Choose canvas.sizing.mode from product context instead of copying a universal 1024px artboard.",
|
|
1070
|
-
"Do not let canvas.upload choose intrinsic-media by default. Upload without explicit sizing resolves to editable-output so source/background images do not own product output size.",
|
|
1071
|
-
"Use intrinsic-media only for true media-viewer or source-native apps where the natural uploaded/generated media size is the product output; record the reason and prove it with intrinsic-media-size acceptance.",
|
|
1072
|
-
"Use editable-output for generated, exportable, shader, poster, badge, wall, banner, thumbnail, procedural, reference-clone, and product-output apps so users always see Aspect ratio, Canvas width, and Canvas height.",
|
|
1073
|
-
"When an uploaded image is a background/source inside the product canvas, keep the current canvas.size, keep Setup/canvas controls visible, and render the image as cover/crop inside the current canvas bounds without letterbox or aspect distortion.",
|
|
1074
|
-
"When no explicit product size is provided, the runtime default canvas is 16:9 at 1920x1080; do not reset a new product-output app to 1:1 unless the product meaning requires it.",
|
|
1075
|
-
"A user-provided, reference, fixed-format, or base/default size is not a reason to remove size controls; model it as canvas.size plus editable-output so the size is an initial value, not a hidden lock.",
|
|
1076
|
-
"Do not use fixed-output for generated product/output apps with export actions. Reserve fixed-output for non-product internal fixtures where width and height truly must never be user-editable, and prove that lock with canvasSizingCoverage fixed-output-size acceptance.",
|
|
1077
|
-
"A reference or previous app lacking a size editor, or defining a fixed-size baseline, is not a fixed-output reason for a generated product app; product-output clones still use editable-output.",
|
|
1078
|
-
"Resolved canvas.size exists for every canvas app, but visible Canvas width and Canvas height controls are mandatory only for editable-output sizing and live in the mandatory runtime Setup section.",
|
|
1079
|
-
"If canvas.size is provided without an explicit sizing mode, defineToolcraft treats it as editable-output and adds Canvas width and Canvas height controls.",
|
|
1080
|
-
"The runtime Canvas width and Canvas height block uses the mandatory headerless Setup controls block; do not add a separate Canvas section label above these fields.",
|
|
1081
|
-
"When the user manually edits Canvas width or Canvas height, the runtime keeps the typed dimension, keeps the other dimension unchanged, switches Aspect ratio to Custom, and shows the reduced current ratio in the custom ratio inputs.",
|
|
1082
|
-
"Aspect ratio presets are the only interaction that may resize both canvas dimensions from a preset; manual size inputs are exact output dimensions.",
|
|
1083
|
-
"For non-vector raster, Canvas 2D, WebGL, and WebGPU previews, set canvas.renderScale: true so the runtime adds Resolution scale after canvas sizing. The scale changes backing pixels from 1 to 2 without changing visible canvas size, and adding/enabling it requires targeted browser evidence that the canvas stays responsive at the selected scale.",
|
|
1084
|
-
"After enabling canvas.renderScale, verify that canvas preview stays responsive while dragging sliders and other high-frequency controls at the selected scale.",
|
|
1085
|
-
"Performance fixes for canvas.renderScale must preserve the selected visual quality; do not silently downsample, stretch a lower-resolution backing canvas, blur output, or clamp canvas.renderScale below the user's chosen value to pass budgets.",
|
|
1086
|
-
"Do not enable canvas.renderScale for DOM/SVG/vector-native previews; preserve vector fidelity through native vector rendering instead of raster supersampling.",
|
|
1087
|
-
],
|
|
1088
|
-
capabilities: ["drag", "zoom", "radar", "upload", "editable-size"],
|
|
1089
|
-
commands: [
|
|
1090
|
-
"canvas.setSize",
|
|
1091
|
-
"canvas.panBy",
|
|
1092
|
-
"canvas.setOffset",
|
|
1093
|
-
"canvas.center",
|
|
1094
|
-
"canvas.zoomIn",
|
|
1095
|
-
"canvas.zoomOut",
|
|
1096
|
-
"canvas.zoomReset",
|
|
1097
|
-
"media.delete",
|
|
1098
|
-
"media.import",
|
|
1099
|
-
"media.reorder",
|
|
1100
|
-
"media.transform",
|
|
1101
|
-
],
|
|
1102
|
-
historyPolicy: "patch",
|
|
1103
|
-
id: "canvas",
|
|
1104
|
-
kind: "canvas",
|
|
1105
|
-
schemaType: "canvas",
|
|
1106
|
-
stateMode: "runtime-owned",
|
|
1107
|
-
visualComponent: "CanvasShell",
|
|
1108
|
-
},
|
|
1109
|
-
persistence: {
|
|
1110
|
-
aiUsageRules: [
|
|
1111
|
-
"Do not write app state to localStorage directly.",
|
|
1112
|
-
"Use schema persistence policy for app state that should survive reload.",
|
|
1113
|
-
"Persistence may include values, canvas, panels, timeline, layers, and media; history is not persisted.",
|
|
1114
|
-
"Use persistence include: [\"media\"] only when runtime media state must survive reload, such as predefined attached files that users can delete, reorder, or transform. Do not use ad hoc storage for media state.",
|
|
1115
|
-
'Apps with visible runtime panels and localStorage persistence must include "panels" so dragged panel positions survive reload.',
|
|
1116
|
-
'Apps with localStorage persistence must include acceptance coverage for changing a user setting, reloading the browser page, and seeing the restored value or product output.',
|
|
1117
|
-
"Settings import/export is a mandatory runtime preset transfer feature; it must not be used to hide or replace broken persistence reload behavior.",
|
|
1118
|
-
"Do not store media blobs, files, or large generated images in localStorage.",
|
|
1119
|
-
],
|
|
1120
|
-
capabilities: ["themePreference", "appStatePolicy"],
|
|
1121
|
-
commands: [],
|
|
1122
|
-
historyPolicy: "never",
|
|
1123
|
-
id: "persistence",
|
|
1124
|
-
kind: "persistence",
|
|
1125
|
-
schemaType: "persistence",
|
|
1126
|
-
stateMode: "runtime-owned",
|
|
1127
|
-
visualComponent: "none",
|
|
1128
|
-
},
|
|
1129
|
-
settingsTransfer: {
|
|
1130
|
-
aiUsageRules: [
|
|
1131
|
-
"Generated apps keep a controls panel so runtime Setup is visible from the first run; product controls are added after that mandatory runtime section.",
|
|
1132
|
-
"Do not gate Export Settings / Import Settings behind complexity thresholds, app size, or prompt wording.",
|
|
1133
|
-
"Do not hand-roll settings import/export through app routes, hidden file inputs, or panelActions.",
|
|
1134
|
-
"Settings transfer appears in the first visible headerless Setup controls-panel block; it imports and exports control values, canvas size, and timeline state.",
|
|
1135
|
-
"App-authored sections must not declare runtime Setup targets such as runtime.settingsTransfer, canvas.aspectRatio, canvas.size.width, canvas.size.height, canvas.renderScale, or panels.timeline.extended; those controls never suppress the mandatory runtime Setup controls.",
|
|
1136
|
-
"When editable-output canvas sizing is enabled, the first visible Setup runtime section contains Export Settings, Import Settings, Aspect ratio, Canvas width, Canvas height, and optional Resolution scale in that order.",
|
|
1137
|
-
"When panels.timeline is enabled, Setup appends the Timeline switch as the last control; when panels.timeline is omitted, the Timeline switch must not appear.",
|
|
1138
|
-
"Keep sticky footer panelActions for product delivery actions only, such as Export PNG, Export Video, Copy, Generate, Apply, or Download.",
|
|
1139
|
-
],
|
|
1140
|
-
capabilities: ["settings-import-export"],
|
|
1141
|
-
commands: ["controls.setValue", "timeline.setCurrentTime", "timeline.setDuration"],
|
|
1142
|
-
historyPolicy: "patch",
|
|
1143
|
-
id: "settingsTransfer",
|
|
1144
|
-
kind: "settings",
|
|
1145
|
-
schemaType: "settingsTransfer",
|
|
1146
|
-
stateMode: "runtime-owned",
|
|
1147
|
-
visualComponent: "SettingsTransfer",
|
|
1148
|
-
},
|
|
1149
|
-
appEntityAcceptance: {
|
|
1150
|
-
aiUsageRules: [
|
|
1151
|
-
"Every app entity introduced by the AI must have an acceptance test that proves its product responsibility.",
|
|
1152
|
-
"Compound controls must declare controlPartCoverage for every semantic value part required by their control type.",
|
|
1153
|
-
"Compound control browser tests must explicitly exercise each required value part, not only one visible sub-control.",
|
|
1154
|
-
"Acceptance tests must fail when an entity is disconnected from runtime state, renderer output, export output, or command side effects.",
|
|
1155
|
-
"Do not accept typecheck, component existence, registered commands, runtime state mutation, renderer input objects, shader uniform presence, or signature strings as final proof.",
|
|
1156
|
-
"Use product-level observables such as rendered pixels, exported image bytes, canvas hash, clipboard payload, cleared media preview, selected layer result, changed viewport, or timeline-rendered frame.",
|
|
1157
|
-
"Any supplied video, GIF, screen-recording, contact-sheet, or extracted-frame reference requires a Video Reference Study before implementation: storyboard frames, frame-to-frame transition analysis, behavior decomposition, and acceptance mapping. Do not implement video references from a single screenshot or high-level summary.",
|
|
1158
|
-
"A generic canvas hash difference is not enough for workload or semantic controls; assert the intended direction of the effect.",
|
|
1159
|
-
"Component variants are accepted entities too; tests should fail if a non-default Toolcraft control variant falls back to the default variant or custom markup.",
|
|
1160
|
-
"Conditional entities require fixtures that make the condition observable.",
|
|
1161
|
-
"Use visibleWhen for mode-, type-, source-, include-, variant-, or count-exclusive sections or controls that do not belong to the current selected state.",
|
|
1162
|
-
"When visibleWhen references a selector for the same product entity or selected branch, keep the selector and its dependent controls in one semantic section. A section that exists only because one selector option is active is not a separate product section just because the branch uses a standalone control.",
|
|
1163
|
-
"When a count/quantity control determines how many sibling controls are available, hide unavailable siblings with visibleWhen; do not render all possible controls while the renderer reads only the first N.",
|
|
1164
|
-
"If a switch/select/segmented/imagePicker/checkbox chooses a branch for the same product entity, controls outside the current branch use visibleWhen, not disabledWhen.",
|
|
1165
|
-
"Do not use schema disabled: true or disabledWhen for generated product controls; the panel should show only controls usable in the current state. Runtime primitives may still have disabled styling internally, but app schemas should model product availability with visibleWhen.",
|
|
1166
|
-
"Do not leave inactive conditional controls visible while making the renderer ignore them.",
|
|
1167
|
-
"If an entity cannot be tested against a product-level observable, remove it from the app schema or ask whether it is required.",
|
|
1168
|
-
],
|
|
1169
|
-
capabilities: ["acceptance-tests", "product-output-verification"],
|
|
1170
|
-
commands: [],
|
|
1171
|
-
historyPolicy: "never",
|
|
1172
|
-
id: "appEntityAcceptance",
|
|
1173
|
-
kind: "composition",
|
|
1174
|
-
schemaType: "appEntityAcceptance",
|
|
1175
|
-
stateMode: "runtime-owned",
|
|
1176
|
-
visualComponent: "none",
|
|
1177
|
-
},
|
|
1178
|
-
performanceAcceptance: {
|
|
1179
|
-
aiUsageRules: [
|
|
1180
|
-
"Custom renderers must define performance budgets for media import, preview updates, control drags, and export/copy before implementation.",
|
|
1181
|
-
"Controls that change renderer workload by changing output dimensions, element count, density, sample count, iteration count, blur/filter radius, shader branch cost, media processing, text layout, or export quality must be tested at min, default, and max values.",
|
|
1182
|
-
"For workload control scenarios, stressFixture is the tested control value. If the app has an independent heavy baseline such as large media, long text, many items, high render scale, or dense source state, declare workloadFixture and apply it before the measured control interaction.",
|
|
1183
|
-
"Hash differs is not enough for workload controls; tests must assert semantic direction, such as density increasing item count or size changes reducing/increasing rendered cells.",
|
|
1184
|
-
"Performance tests must use representative fixtures and the same renderer/export path as the running app, not only tiny 32px fixtures or isolated helper state.",
|
|
1185
|
-
"Media-import workload fixtures and media workload baselines must use fixture kind \"media\" with numeric width and height at least 1920x1080-equivalent; 640x480 preview fixtures cannot satisfy upload, effect-control, or image-processing performance coverage.",
|
|
1186
|
-
"Expensive renderers must cache decoded media, source pixels, glyph atlases, gradients, and other reusable inputs by media id, canvas size, and stable control keys.",
|
|
1187
|
-
"Slider drags and high-frequency controls must debounce or coalesce preview work, cancel stale async renders, and avoid re-decoding media on every control change.",
|
|
1188
|
-
"Performance matrices must declare rendererWorkload as none, simple-composition, text-output, vector-output, or pixel-output.",
|
|
1189
|
-
"A full performance checkpoint must run only when the first working app version exists or the user requests performance, lag, jank, animation speed, drag/zoom stabilization work, or otherwise complains about performance; use the agent-controlled browser first and this app's verify:perf script only as the Playwright fallback.",
|
|
1190
|
-
"Renderer, canvas, animation, export, timeline, layers, canvas.renderScale, bug fixes, and performance-sensitive control changes use targeted functional/browser checks first and targeted performance scenarios only for touched workload, viewport, or export paths.",
|
|
1191
|
-
"Performance fixes must preserve selected output and preview quality; do not reduce image quality, selected renderScale, export resolution, source media fidelity, or canvas backing pixels as the hidden way to pass budgets.",
|
|
1192
|
-
"When canvas or slider interactions lag, diagnose where the slowdown comes from before changing output quality: renderer technique, React update frequency, decoded media, shader/program setup, buffer uploads, layout work, async render cancellation, or animation scheduling.",
|
|
1193
|
-
"Renderer specs must include a Renderer Technique Decision Matrix with sourceRepresentation, productRepresentation, previewRenderer, exportRenderer, rendererWorkload, rendererStrategy, whyNotAlternativeStrategies, fidelityRisks, and performanceRisks.",
|
|
1194
|
-
"Custom renderer apps must mirror the Renderer Technique Decision Matrix in typed rendererTechnique config so validation can reject contradictory renderer choices.",
|
|
1195
|
-
"Custom renderer specs must include a Renderer Layer Inventory and mirror it in typed rendererTechnique.layers so dense raster backgrounds cannot silently rasterize semantic foreground output.",
|
|
1196
|
-
"Custom renderer apps must declare rendererPipeline with render passes, cache keys, execution location, preview/export quality, and interaction invalidation before implementation.",
|
|
1197
|
-
"Render Pipeline Inventory must explain which runtime targets invalidate each expensive pass; high-frequency interactions such as animation frames, drag, zoom, pan, timeline playback, and mask movement must not invalidate upstream decode/preprocess/pixel-transform work unless that target truly changes the upstream result.",
|
|
1198
|
-
"Cache-sensitive render passes such as decode, preprocess, pixel-transform, text-layout, rasterize, and composite must declare cache keys so tests can reject full recomputation on every control change.",
|
|
1199
|
-
"Semantic foreground output such as product lines, shapes, icons, text, object bounds, and meaningful markers should use DOM or SVG by default; dense raster backgrounds do not justify rasterizing low-count foreground geometry or text.",
|
|
1200
|
-
"Editing handles must be DOM/SVG overlays, excluded from export, and written through runtime state instead of being drawn into the product raster layer.",
|
|
1201
|
-
"Product foreground and editing handle renderer layers must declare uiSelector so browser tests can verify the visible layer exists.",
|
|
1202
|
-
'productRepresentation "mixed" is valid only when rendererTechnique.layers proves at least two different content families.',
|
|
1203
|
-
"Choose renderer technique from product context, not convenience or novelty. Preserve reference renderer technology in reference-runtime-clone mode unless a concrete blocker and replacement acceptance tests are named.",
|
|
1204
|
-
"Do not switch renderer technology just because it seems more modern or faster. Preview and export may use different renderers only when the decision matrix explains why and export/copy remains product-quality.",
|
|
1205
|
-
"Choose renderer workload by product fidelity before choosing rendering technology: ASCII, glyph grids, code art, subtitles, typography, or monospace text products are text-output unless the product intentionally rasterizes them into per-pixel effects.",
|
|
1206
|
-
"Text-output and vector-output visible previews must preserve native output fidelity. Do not render a low-resolution offscreen canvas or texture and upscale it to the product size.",
|
|
1207
|
-
"Pixel-output renderers must treat WebGL/WebGPU as the default candidate even when the scene is static; Canvas 2D is allowed only when measured worst-case evidence shows the CPU path preserves quality and remains responsive.",
|
|
1208
|
-
"Procedural pixel renderers, shader-like effects, animated mesh gradients, and large exportable previews should use WebGL or WebGPU for pixel work instead of main-thread ImageData loops.",
|
|
1209
|
-
"Detail-heavy Canvas 2D pixel/media renderers may stay on CPU only when rendererTechnique records measured stress evidence for rejecting WebGL/WebGPU; if the heavy media stress fails, move pixel work to GPU instead of lowering quality.",
|
|
1210
|
-
"WebGL and WebGPU renderers must initialize contexts, programs, shaders, pipelines, textures, and large buffers once, then update uniforms or stable buffers when controls change.",
|
|
1211
|
-
"For keyframe or playback renderers, texture upload and media decode must be keyed to source media/resource changes, not to timeline time or evaluated settings. Timeline-only updates must reuse decoded media and existing GPU resources.",
|
|
1212
|
-
"Do not create WebGL/WebGPU contexts, shader programs, textures, or requestAnimationFrame loops directly in the React render path.",
|
|
1213
|
-
"Animation loops must cancel scheduled frames during cleanup.",
|
|
1214
|
-
"Animated preview renderers must suspend or coalesce non-essential animation work while the user drags, pans, pinches, zooms, or centers the canvas viewport, then resume from the correct timeline or autonomous time without changing the user's play/pause state.",
|
|
1215
|
-
"If a generated app uses ImageData, getImageData, or putImageData for procedural output, performance validation must fail unless rendererTechnique records measured WebGL/WebGPU comparison evidence that the CPU path preserves quality and responsiveness, or the renderer is moved to GPU.",
|
|
1216
|
-
"Performance matrices must declare rendererStrategy so tests can distinguish none, dom, svg, canvas-2d, webgl, and webgpu renderer paths.",
|
|
1217
|
-
"Browser verification must interact with the actual UI, exercise worst-case control values, and fail if the app freezes, creates runaway render loops, drops canvas zoom/offset, or misses the performance budget.",
|
|
1218
|
-
"If a renderer cannot meet the budget, first optimize renderer technique, caching, invalidation, scheduling, and critical-path work. Only change exposed product ranges, work units, or controls after recording measured evidence that the requested quality ceiling is impossible; do not silently reduce product quality to pass budgets.",
|
|
1219
|
-
],
|
|
1220
|
-
capabilities: ["performance-budgets", "workload-control-tests"],
|
|
1221
|
-
commands: [],
|
|
1222
|
-
historyPolicy: "never",
|
|
1223
|
-
id: "performanceAcceptance",
|
|
1224
|
-
kind: "composition",
|
|
1225
|
-
schemaType: "performanceAcceptance",
|
|
1226
|
-
stateMode: "runtime-owned",
|
|
1227
|
-
visualComponent: "none",
|
|
1228
|
-
},
|
|
1229
|
-
referenceRuntimeClone: {
|
|
1230
|
-
aiUsageRules: [
|
|
1231
|
-
'Use transferMode: "reference-runtime-clone" when the user asks to port, clone, copy, or reproduce an existing app exactly.',
|
|
1232
|
-
"Preserve the reference runtime as the source of truth instead of replacing it with a new renderer or timeline model.",
|
|
1233
|
-
"Port requestAnimationFrame loops, refs, mutable particle/object state, connection state, spawn/update cadence, lifetime rules, pause/resume, export/copy, canvas sizing, and media lifecycle when the reference depends on them.",
|
|
1234
|
-
"Keep Toolcraft as the shell: defineToolcraft, ToolcraftApp, schema controls, canvasContent, fileDrop, panelActions, and runtime commands.",
|
|
1235
|
-
"Reference clone timeline choice is based on timeline behavior, not only on whether the reference draws a timeline-shaped UI.",
|
|
1236
|
-
"If the reference has Play/Pause, Restart from beginning, current time/progress, duration, loop, scrub, selected range, trim handles, or video export timing, write a Reference Timeline Inventory before choosing a timeline mode.",
|
|
1237
|
-
'Use referenceTimeline.mode "toolcraft-playback" for plain transport behavior such as play/pause, restart, duration/progress, loop, scrub, or export at time.',
|
|
1238
|
-
'Use referenceTimeline.mode "toolcraft-keyframes" when controls need keyframe diamonds, expanded keyframe rows, easing, or editable keyframes.',
|
|
1239
|
-
'Use referenceTimeline.mode "none" only when the reference has no user-facing transport behavior at all.',
|
|
1240
|
-
"Reference clone specs must list every detected transport behavior explicitly, including pause-resume, restart, time-progress, export-at-time, playback, scrub, duration, loop, and keyframes when present.",
|
|
1241
|
-
'Toolcraft reference timelines must declare referenceTimeline.loopDuration with source "reference", "user-request", or "product-derived", plus seconds and evidence; runtime/template fallback 8s is not a valid source.',
|
|
1242
|
-
"panels.timeline.defaultDurationSeconds must match referenceTimeline.loopDuration.seconds for referenceTimeline.mode toolcraft-playback/toolcraft-keyframes.",
|
|
1243
|
-
"Do not create right-panel controls named or targeted as Play, Pause, Paused, Animate, Restart animation, or equivalent app-wide transport toggles.",
|
|
1244
|
-
'Do not downgrade custom reference timelines to panels.timeline mode "playback". State buttons, trim handles, selected-range playback, or range export require referenceTimeline.mode "custom-reference-timeline" and dedicated acceptance.',
|
|
1245
|
-
"Generated reference clone apps must declare starterTransferMode.referenceTimeline with mode none, toolcraft-playback, toolcraft-keyframes, or custom-reference-timeline.",
|
|
1246
|
-
"Custom reference timeline behavior needs referenceTimelineCoverage entries such as state-jump, trim-range, range-playback, all-range, jump-to-trim-start, and export-range.",
|
|
1247
|
-
"Reference clone acceptance must include referenceCoverage rows for canvas sizing, control mapping, renderer state, and any renderer loop, spawn/update cadence, pause/resume, export/copy, or media lifecycle behavior in the reference.",
|
|
1248
|
-
"Video reference assets used in a reference clone also require starterTransferMode.videoReferenceStudy with storyboard frames, frame-to-frame transition analysis, behavior decomposition, and acceptance mapping.",
|
|
1249
|
-
"Browser tests must compare reference behavior or a reference-derived baseline, not only Toolcraft state mutation.",
|
|
1250
|
-
],
|
|
1251
|
-
capabilities: [
|
|
1252
|
-
"reference-runtime-clone",
|
|
1253
|
-
"reference-behavior-acceptance",
|
|
1254
|
-
"reference-timeline-inventory",
|
|
1255
|
-
"canvasContent-renderer",
|
|
1256
|
-
],
|
|
1257
|
-
commands: [],
|
|
1258
|
-
historyPolicy: "never",
|
|
1259
|
-
id: "referenceRuntimeClone",
|
|
1260
|
-
kind: "composition",
|
|
1261
|
-
schemaType: "transferMode",
|
|
1262
|
-
stateMode: "runtime-owned",
|
|
1263
|
-
visualComponent: "canvasContent",
|
|
1264
|
-
},
|
|
1265
|
-
controlLabels: {
|
|
1266
|
-
aiUsageRules: [
|
|
1267
|
-
"Control labels must be short UI names, usually one to three words.",
|
|
1268
|
-
"Do not put explanations, formulas, units, parenthetical hints, or usage instructions in control labels.",
|
|
1269
|
-
"A concise property label such as Speed, Color, Size, or Opacity is allowed when the nearest visible section or group clearly names the affected product entity.",
|
|
1270
|
-
"When the section is generic, mixed, missing, or otherwise weak context, include the affected entity or role in the label: Pattern color, Background opacity, Wave speed, Stroke width.",
|
|
1271
|
-
"Acceptance validators suggest semantic replacement labels for weak generic labels; fix the schema label instead of relying on runtime fallback rewriting.",
|
|
1272
|
-
"Controls-panel sections should stay discrete: two to seven product controls is the normal size, and larger sections must split by product sub-entity or workflow stage.",
|
|
1273
|
-
"Generated product apps must export starterControlSectionInventory beside acceptance. Every product controls section declares title, exact targets, groupingReason, and entity or workflowStage; intentional splits of one target entity require workflowStage and splitReason on every split section.",
|
|
1274
|
-
"Section splitting must preserve dependency cohesion: a selector stays with the visibleWhen controls it gates when they share the same target entity or selected branch. Use internal spacing/dividers or a more specific section title before splitting dependent branch controls away.",
|
|
1275
|
-
"Every app-authored controls-panel body section must have a short meaningful visible title. Runtime-created Setup renders as the first visible headerless controls block with no title, reset action, collapse button, or collapsed state; sticky footer action sections use the technical title Export but render without a visible heading.",
|
|
1276
|
-
"Every visible app-authored controls-panel section title renders through the standard 36px collapsible header row with vertically centered text and the runtime collapse icon; generated apps must not hand-build section headers.",
|
|
1277
|
-
"Controls-panel section expand and collapse uses the standard runtime height/opacity animation; generated apps must not replace it with instant custom section visibility.",
|
|
1278
|
-
"Controls-panel section collapsed/expanded state persists as a runtime UI preference per app. It is not undo/redo state, not settings import/export state, and Reset controls must not clear it. Runtime Setup is not collapsible; sticky footer Export sections are not collapsible.",
|
|
1279
|
-
"Ordinary controls-panel section headers expose the runtime section reset action before the collapse button; it dispatches controls.resetTargets and restores only that section's control targets to their schema defaultValue.",
|
|
1280
|
-
"Runtime Setup and ordinary controls-panel body sections use 8px top spacing and 24px bottom spacing for their control content. Sticky footer action sections keep their dedicated spacing.",
|
|
1281
|
-
"Broad section titles such as Flow, Icon, Shapes, Scene, Text, Typography, or Motion are only valid for small cohesive groups; use specific titles such as Flow Motion, Flow Geometry, Letter Burst, Shape Colors, Logo Glow, Logo Plate, or Text Block for larger groups.",
|
|
1282
|
-
"Section titles in one controls panel must be unique.",
|
|
1283
|
-
"Use section titles, option labels, tests, or renderer/spec prose for details instead of long field labels.",
|
|
1284
|
-
"Bad: Grid Density (every Nth). Good: Grid Density, with Every 6th as the select option label.",
|
|
1285
|
-
"Use control.description for the short help tooltip shown beside visible labels. It must describe the product behavior or output affected by the control, not restate the label.",
|
|
1286
|
-
"Do not write label-recap descriptions such as Adjusts Opacity, Controls Speed, or Sets Background.",
|
|
1287
|
-
"If there is no useful product-specific explanation, omit control.description; the runtime should not show a help tooltip for that label.",
|
|
1288
|
-
"Do not add control.description to sequential colors such as Color 1, Color 2, or simple palette controls such as Spread when the section title already names the color or palette context.",
|
|
1289
|
-
"For compound controls such as FontPicker, do not use control.description to enumerate the control's owned fields. FontPicker descriptions must not recap font family, weight, size, case, color, opacity, letter spacing, or line height; use description only for non-obvious product scope or omit it.",
|
|
1290
|
-
"The runtime renders a filled Phosphor question icon beside each visible ControlFieldLabel; generated apps must not hand-build their own help icon beside built-in labels.",
|
|
1291
|
-
"If a source label is unavoidably long, keep the visible label concise and rely on the native title tooltip for the full text.",
|
|
1292
|
-
],
|
|
1293
|
-
capabilities: ["short-labels", "control-description-tooltip", "native-title-tooltip"],
|
|
1294
|
-
commands: [],
|
|
1295
|
-
historyPolicy: "never",
|
|
1296
|
-
id: "controlLabels",
|
|
1297
|
-
kind: "composition",
|
|
1298
|
-
schemaType: "controlLabels",
|
|
1299
|
-
stateMode: "runtime-owned",
|
|
1300
|
-
visualComponent: "ControlFieldLabel",
|
|
1301
|
-
},
|
|
1302
|
-
controlsPanel: panel("controlsPanel", "ControlsPanel", "right", ["left", "right"], "handle"),
|
|
1303
|
-
layersPanel: {
|
|
1304
|
-
...panel("layersPanel", "LayersPanel", "left", ["left", "right"], "handle"),
|
|
1305
|
-
aiUsageRules: [
|
|
1306
|
-
"Enable panels.layers only when the app needs editable layer selection, ordering, grouping, visibility, or multi-object media management.",
|
|
1307
|
-
"Do not enable the layers panel for single-layer apps.",
|
|
1308
|
-
"If the user intent is ambiguous, ask whether layer management is required before enabling panels.layers.",
|
|
1309
|
-
"When layers are enabled, layer-specific controls should target selectedLayer.* and apply to the currently selected runtime layer.",
|
|
1310
|
-
"Do not use selectedLayer.* targets when panels.layers is disabled; single-layer apps use app-specific targets.",
|
|
1311
|
-
"Layer-enabled apps need layerCoverage acceptance for selection, visibility, reorder, and grouping.",
|
|
1312
|
-
"Every selectedLayer.* control needs selected-layer-controls acceptance proving it edits the currently selected layer output.",
|
|
1313
|
-
"Layer browser coverage must use real LayersPanel rows and buttons, not direct layers.* command dispatch.",
|
|
1314
|
-
"Layer-enabled custom renderers need layers.interactions viewport-stability coverage around real selection, visibility, reorder or grouping, and selected-layer output checks.",
|
|
1315
|
-
],
|
|
1316
|
-
capabilities: [
|
|
1317
|
-
"draggable",
|
|
1318
|
-
"snap",
|
|
1319
|
-
"doubleClickReset",
|
|
1320
|
-
"dragMode:handle",
|
|
1321
|
-
"groups",
|
|
1322
|
-
"selection",
|
|
1323
|
-
"visibility",
|
|
1324
|
-
],
|
|
1325
|
-
commands: [
|
|
1326
|
-
"layers.add",
|
|
1327
|
-
"layers.delete",
|
|
1328
|
-
"layers.moveToGroup",
|
|
1329
|
-
"layers.rename",
|
|
1330
|
-
"layers.reorder",
|
|
1331
|
-
"layers.select",
|
|
1332
|
-
"layers.toggleCollapsed",
|
|
1333
|
-
"layers.toggleVisibility",
|
|
1334
|
-
],
|
|
1335
|
-
},
|
|
1336
|
-
timelinePanel: {
|
|
1337
|
-
...panel("timelinePanel", "TimelinePanel", "top", ["top", "bottom"], "panel"),
|
|
1338
|
-
aiUsageRules: [
|
|
1339
|
-
"Any product output animation must enable the top Toolcraft timeline; do not ship animated product output with only local requestAnimationFrame playback.",
|
|
1340
|
-
"Before choosing no timeline for any animated product, write an Animation Intent Inventory: product transport, editable keyframes, or autonomous decorative output, plus the user-facing time behaviors present or intentionally absent.",
|
|
1341
|
-
'User-requested product animation defaults to panels.timeline mode "playback" unless the spec explicitly declares autonomous decorative/self-running output with no play, pause, scrub, duration, loop, export-at-time behavior, or video export.',
|
|
1342
|
-
'Any product app with Export Video must enable the top Toolcraft timeline: use panels.timeline mode "playback" for product animation transport, or mode "keyframes" when exported animation is driven by keyframes.',
|
|
1343
|
-
'Use panels.timeline: { mode: "playback" } when the product needs user-facing play, pause, scrubbing, duration, loop, restart, time progress, export-at-time controls, or video export.',
|
|
1344
|
-
'When panels.timeline is enabled for a new Toolcraft app, appTransferMode.animationIntent must match it: mode "timeline-playback" for playback, or mode "timeline-keyframes" for keyframes.',
|
|
1345
|
-
"Playback renderers must consume runtime timeline state; pause freezes output, scrubbing renders a deterministic frame, and the full animation cycle maps to state.timeline.durationSeconds instead of a local fixed duration.",
|
|
1346
|
-
"When the product has a known loop duration, declare it as panels.timeline.defaultDurationSeconds; the runtime timeline duration starts from that loop duration instead of an unrelated 8s default.",
|
|
1347
|
-
'Timeline animation intent must declare loopDuration with source "reference", "user-request", or "product-derived", plus seconds and evidence; runtime/template fallback 8s is not a valid source.',
|
|
1348
|
-
"panels.timeline.defaultDurationSeconds must match animationIntent.loopDuration.seconds for playback/keyframe animation, so the initial timeline UI shows the declared product loop instead of a generic default.",
|
|
1349
|
-
"Video export renderers must render deterministic frames from runtime timeline timestamps and duration; do not treat autonomous wall-clock time or captureStream recording time as the source of product duration.",
|
|
1350
|
-
"Playback renderers may compute an initial loop duration default during app initialization or reset, but must not watch state.timeline.durationSeconds and dispatch timeline.setDuration back to a computed local duration. User-edited timeline duration becomes the loop duration source of truth after initialization or reset.",
|
|
1351
|
-
"Playback renderers should use getToolcraftTimelineLoopTime or getToolcraftTimelineLoopProgress to derive product loop phase from state.timeline.currentTimeSeconds and state.timeline.durationSeconds; do not hand-roll wall-clock, fixed-duration, mirror, yoyo, ping-pong, or reverse phase math.",
|
|
1352
|
-
"Product animation loop means a seamless forward-only cycle by default: motion advances in one direction, first and last frames stitch without a visible jump, and mirror/yoyo/ping-pong/reverse loops require explicit user request.",
|
|
1353
|
-
"Changing timeline duration must preserve seamless forward-loop semantics: one full product animation cycle maps from 0 to state.timeline.durationSeconds, first and last frames still stitch, direction does not reverse, and changing duration must not switch the renderer to wall-clock or fixed local speed.",
|
|
1354
|
-
"When non-looping playback reaches the end, pressing Play again restarts playback from time 0.",
|
|
1355
|
-
"Intrinsic-media upload timelines must stay paused at time 0 until source media exists; clearing the last media asset must pause and reset playback.",
|
|
1356
|
-
'Use panels.timeline: { mode: "keyframes" } or panels.timeline: true only when controls need keyframe diamonds, expanded timeline rows, easing, or keyframe editing.',
|
|
1357
|
-
"In keyframes mode, Toolcraft infers keyframe diamonds from control type; AI must not manually pick a smaller subset of slider/vector/color-style controls.",
|
|
1358
|
-
"Keyframe state stores typed control values; valueLabel is display-only and must never be parsed by renderers or tests as the source of truth.",
|
|
1359
|
-
"Custom renderers with keyframes must consume evaluateToolcraftTimelineValues or useToolcraftEvaluatedValues for keyframed settings instead of raw state.values for those targets.",
|
|
1360
|
-
"Every inferred keyframe-capable control must be evaluated from runtime timeline keyframes and needs acceptance proving diamond creation, row creation, keyframe updates, scrub/playback evaluation, and product output change.",
|
|
1361
|
-
"Keyframe custom renderers must prove zoom, radar, and canvas viewport stability while expanding the timeline, creating keyframes, and scrubbing or playing the timeline.",
|
|
1362
|
-
"Keyframe renderers must not re-decode media or re-upload source textures on timeline ticks, scrubs, playback, or evaluated setting changes.",
|
|
1363
|
-
"Timeline-driven preview renderers must suspend or coalesce non-essential animation work during canvas drag, pan, pinch, zoom, and radar/center interactions without mutating the user's timeline play/pause state.",
|
|
1364
|
-
"Use keyframeable: false only on controls that are structurally unsupported by the shared keyframe capability helper; capable controls cannot opt out to hide broken animation wiring.",
|
|
1365
|
-
"Right-panel animation controls may tune renderer parameters such as mode, intensity, speed, or stagger only after animation intent is declared; they must not replace top timeline transport.",
|
|
1366
|
-
"Do not put Pause or Resume in panelActions; playback belongs to TimelinePanel transport controls.",
|
|
1367
|
-
"Do not replace TimelinePanel with an app-level playback, transport, or timeline panel to avoid runtime performance issues; fix the Toolcraft runtime clock/state path instead.",
|
|
1368
|
-
'Custom timeline UI is allowed only for explicit referenceTimeline.mode "custom-reference-timeline" transfers with browser-backed referenceTimelineCoverage.',
|
|
1369
|
-
'When panels.timeline is enabled, runtime inserts a Setup switch labeled "Timeline" as the last runtime setup control after Resolution scale.',
|
|
1370
|
-
"The Timeline Setup switch controls only compact versus extended runtime presentation: off shows the compact Play-only transport, on shows the extended timeline with scrubber, duration, loop, and keyframe UI. It must not stop playback, change keyframes, affect export, enter product values, or be reset by Reset controls/settings transfer.",
|
|
1371
|
-
"Playback-only timelines stay collapsed and do not show keyframe diamonds or expanded keyframe rows.",
|
|
1372
|
-
"If timeline verification fails, wire the renderer to runtime timeline state or remove panels.timeline.",
|
|
1373
|
-
],
|
|
1374
|
-
capabilities: [
|
|
1375
|
-
"draggable",
|
|
1376
|
-
"snap",
|
|
1377
|
-
"doubleClickReset",
|
|
1378
|
-
"dragMode:panel",
|
|
1379
|
-
"duration",
|
|
1380
|
-
"keyframes",
|
|
1381
|
-
"playback",
|
|
1382
|
-
],
|
|
1383
|
-
commands: [
|
|
1384
|
-
"timeline.changeKeyframeEasing",
|
|
1385
|
-
"timeline.deleteControlKeyframes",
|
|
1386
|
-
"timeline.deleteKeyframe",
|
|
1387
|
-
"timeline.moveKeyframe",
|
|
1388
|
-
"timeline.selectKeyframe",
|
|
1389
|
-
"panels.setHidden",
|
|
1390
|
-
"timeline.setCurrentTime",
|
|
1391
|
-
"timeline.setDuration",
|
|
1392
|
-
"timeline.setPlaying",
|
|
1393
|
-
"timeline.toggleLoop",
|
|
1394
|
-
"timeline.togglePlayback",
|
|
1395
|
-
],
|
|
1396
|
-
},
|
|
1397
|
-
toolbar: {
|
|
1398
|
-
...panel("toolbar", "ToolbarPanel", "bottom", ["top", "bottom"], "panel"),
|
|
1399
|
-
aiUsageRules: [
|
|
1400
|
-
"Toolbar history owns Undo and Redo buttons plus runtime keyboard shortcuts.",
|
|
1401
|
-
"Do not add app-level Cmd/Ctrl+Z, Cmd/Ctrl+Shift+Z, or Ctrl+Y listeners; use toolbar history and runtime commands.",
|
|
1402
|
-
"Undo/redo keyboard shortcuts must not fire while the user is typing into inputs, textareas, selects, or contentEditable value labels.",
|
|
1403
|
-
],
|
|
1404
|
-
capabilities: [
|
|
1405
|
-
"draggable",
|
|
1406
|
-
"snap",
|
|
1407
|
-
"doubleClickReset",
|
|
1408
|
-
"history",
|
|
1409
|
-
"keyboardShortcuts",
|
|
1410
|
-
"zoom",
|
|
1411
|
-
"radar",
|
|
1412
|
-
],
|
|
1413
|
-
commands: [
|
|
1414
|
-
"history.undo",
|
|
1415
|
-
"history.redo",
|
|
1416
|
-
"canvas.center",
|
|
1417
|
-
"canvas.zoomIn",
|
|
1418
|
-
"canvas.zoomOut",
|
|
1419
|
-
"canvas.zoomReset",
|
|
1420
|
-
],
|
|
1421
|
-
kind: "toolbar",
|
|
1422
|
-
},
|
|
11
|
+
...TOOLCRAFT_INPUT_COMPONENT_CONTRACTS,
|
|
12
|
+
...TOOLCRAFT_CHOICE_COMPONENT_CONTRACTS,
|
|
13
|
+
...TOOLCRAFT_VISUAL_COMPONENT_CONTRACTS,
|
|
14
|
+
...TOOLCRAFT_MEDIA_CUSTOM_COMPONENT_CONTRACTS,
|
|
15
|
+
...TOOLCRAFT_RUNTIME_COMPONENT_CONTRACTS,
|
|
1423
16
|
} as const satisfies Record<string, ToolcraftComponentContract>;
|
|
1424
17
|
|
|
1425
18
|
export type ToolcraftComponentContractId = keyof typeof TOOLCRAFT_COMPONENT_CONTRACTS;
|
|
1426
19
|
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
20
|
+
type ToolcraftControlContractId = {
|
|
21
|
+
[Id in ToolcraftComponentContractId]:
|
|
22
|
+
(typeof TOOLCRAFT_COMPONENT_CONTRACTS)[Id] extends { kind: "control" }
|
|
23
|
+
? Id
|
|
24
|
+
: Id extends "settingsTransfer"
|
|
25
|
+
? Id
|
|
26
|
+
: never;
|
|
27
|
+
}[ToolcraftComponentContractId];
|
|
1432
28
|
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
}
|
|
29
|
+
export type ToolcraftBuiltInControlType = Exclude<
|
|
30
|
+
ToolcraftControlContractId,
|
|
31
|
+
"customControl"
|
|
32
|
+
>;
|
|
1438
33
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
readonly visualComponent: VisualComponent;
|
|
1458
|
-
} {
|
|
1459
|
-
return {
|
|
1460
|
-
defaultSectionLayout,
|
|
1461
|
-
historyPolicy: "patch",
|
|
1462
|
-
id,
|
|
1463
|
-
kind: "control",
|
|
1464
|
-
labelPolicy,
|
|
1465
|
-
schemaType: id,
|
|
1466
|
-
stateMode: "controlled",
|
|
1467
|
-
visualComponent,
|
|
1468
|
-
};
|
|
34
|
+
export const TOOLCRAFT_BUILT_IN_CONTROL_TYPES = Object.freeze(
|
|
35
|
+
Object.values(TOOLCRAFT_COMPONENT_CONTRACTS)
|
|
36
|
+
.filter(
|
|
37
|
+
(contract) =>
|
|
38
|
+
(contract.kind === "control" || contract.id === "settingsTransfer") &&
|
|
39
|
+
contract.id !== "customControl",
|
|
40
|
+
)
|
|
41
|
+
.map((contract) => contract.schemaType),
|
|
42
|
+
) as readonly ToolcraftBuiltInControlType[];
|
|
43
|
+
|
|
44
|
+
const toolcraftBuiltInControlTypes = new Set<string>(
|
|
45
|
+
TOOLCRAFT_BUILT_IN_CONTROL_TYPES,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
export function isToolcraftBuiltInControlType(
|
|
49
|
+
value: string,
|
|
50
|
+
): value is ToolcraftBuiltInControlType {
|
|
51
|
+
return toolcraftBuiltInControlTypes.has(value);
|
|
1469
52
|
}
|
|
1470
53
|
|
|
1471
|
-
function
|
|
1472
|
-
const Id extends string,
|
|
1473
|
-
const VisualComponent extends string,
|
|
1474
|
-
const Placement extends ToolcraftPanelPlacement,
|
|
1475
|
-
const SnapEdges extends readonly ToolcraftPanelSnapEdge[],
|
|
1476
|
-
const DragMode extends "handle" | "panel",
|
|
1477
|
-
>(
|
|
54
|
+
export function getToolcraftComponentContract<const Id extends ToolcraftComponentContractId>(
|
|
1478
55
|
id: Id,
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
snapEdges: SnapEdges,
|
|
1482
|
-
dragMode: DragMode,
|
|
1483
|
-
): {
|
|
1484
|
-
readonly aiUsageRules: readonly [`Render ${VisualComponent} only through PanelHost.`];
|
|
1485
|
-
readonly capabilities: readonly [
|
|
1486
|
-
"draggable",
|
|
1487
|
-
"snap",
|
|
1488
|
-
"doubleClickReset",
|
|
1489
|
-
`dragMode:${DragMode}`,
|
|
1490
|
-
];
|
|
1491
|
-
readonly defaultPlacement: Placement;
|
|
1492
|
-
readonly historyPolicy: "optional";
|
|
1493
|
-
readonly id: Id;
|
|
1494
|
-
readonly kind: "panel";
|
|
1495
|
-
readonly requiredWrapper: "PanelHost";
|
|
1496
|
-
readonly schemaType: Id;
|
|
1497
|
-
readonly snapEdges: SnapEdges;
|
|
1498
|
-
readonly stateMode: "runtime-owned";
|
|
1499
|
-
readonly visualComponent: VisualComponent;
|
|
1500
|
-
} {
|
|
1501
|
-
return {
|
|
1502
|
-
aiUsageRules: [`Render ${visualComponent} only through PanelHost.`],
|
|
1503
|
-
capabilities: [
|
|
1504
|
-
"draggable",
|
|
1505
|
-
"snap",
|
|
1506
|
-
"doubleClickReset",
|
|
1507
|
-
`dragMode:${dragMode}` as const,
|
|
1508
|
-
],
|
|
1509
|
-
defaultPlacement,
|
|
1510
|
-
historyPolicy: "optional",
|
|
1511
|
-
id,
|
|
1512
|
-
kind: "panel",
|
|
1513
|
-
requiredWrapper: "PanelHost",
|
|
1514
|
-
schemaType: id,
|
|
1515
|
-
snapEdges,
|
|
1516
|
-
stateMode: "runtime-owned",
|
|
1517
|
-
visualComponent,
|
|
1518
|
-
};
|
|
56
|
+
): (typeof TOOLCRAFT_COMPONENT_CONTRACTS)[Id] {
|
|
57
|
+
return TOOLCRAFT_COMPONENT_CONTRACTS[id];
|
|
1519
58
|
}
|