@pixel-point/toolcraft 0.0.16 → 0.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generate-performance-iteration-execution.test.mjs +2 -2
- package/src/generate-test-demand-only-lifecycle.mjs +14 -3
- package/src/generate-test-dependency-sandbox.mjs +42 -5
- package/src/generate-test-doc-assertions.mjs +68 -18
- package/src/generate-test-doc-assertions.test.mjs +22 -0
- package/src/generate-test-file-assertions.mjs +43 -76
- package/src/generate-test-output-assertions.mjs +95 -0
- package/src/generate-test-package-assertions.mjs +6 -0
- package/src/generate-test-performance-boundary-assertions.mjs +45 -0
- package/src/generate-test-product-fixture.mjs +1 -0
- package/src/generate-test-product-fixture.test.mjs +18 -0
- package/src/generate-test-product-iteration.mjs +1 -0
- package/src/generate-test-product-iteration.test.mjs +1 -0
- package/src/generate-test-standalone-delivery-stages.mjs +14 -6
- package/src/generate.test.mjs +14 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +12 -9
- package/templates/runtime/contracts/component-contracts.choices.ts +10 -9
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +17 -2
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +1 -1
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +1 -1
- package/templates/runtime/contracts/component-contracts.runtime.ts +3 -2
- package/templates/runtime/contracts/decision-contracts.test.ts +25 -4
- package/templates/runtime/contracts/decision-contracts.ts +3 -3
- package/templates/runtime/contracts/performance-verification-policy.test.ts +59 -6
- package/templates/runtime/contracts/performance-verification-policy.ts +5 -2
- package/templates/runtime/export/artifact-download.test.ts +71 -0
- package/templates/runtime/export/artifact-download.ts +80 -0
- package/templates/runtime/export/artifact-export-request.ts +23 -0
- package/templates/runtime/export/artifact-export-settings.test.ts +75 -0
- package/templates/runtime/export/artifact-export-settings.ts +96 -0
- package/templates/runtime/export/artifact-frame-renderer.test.ts +107 -0
- package/templates/runtime/export/artifact-frame-renderer.ts +96 -0
- package/templates/runtime/export/artifact-frame-state.test.ts +54 -0
- package/templates/runtime/export/artifact-frame-state.ts +44 -0
- package/templates/runtime/export/artifact-scene-frame.test.ts +84 -0
- package/templates/runtime/export/artifact-scene-frame.ts +118 -0
- package/templates/runtime/export/export-background.ts +65 -0
- package/templates/runtime/export/export-error.ts +43 -0
- package/templates/runtime/export/export.test.ts +6 -186
- package/templates/runtime/export/image-artifact-export.test.ts +111 -0
- package/templates/runtime/export/image-artifact-export.ts +145 -0
- package/templates/runtime/export/index.ts +14 -1
- package/templates/runtime/export/product-export-renderer.test.ts +77 -0
- package/templates/runtime/export/product-export-renderer.ts +63 -0
- package/templates/runtime/export/video-artifact-export.test.ts +166 -0
- package/templates/runtime/export/video-artifact-export.ts +164 -0
- package/templates/runtime/export/video-encoding-backend.ts +124 -0
- package/templates/runtime/export/video-encoding-policy.test.ts +68 -0
- package/templates/runtime/export/video-encoding-policy.ts +86 -0
- package/templates/runtime/export/video-frame-schedule.test.ts +58 -0
- package/templates/runtime/export/video-frame-schedule.ts +42 -0
- package/templates/runtime/index.ts +1 -0
- package/templates/runtime/react/app-shell/runtime-public-api-runtime.test.tsx +291 -0
- package/templates/runtime/react/app-shell/runtime-public-api-test-support.ts +21 -0
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +4 -303
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +12 -27
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +22 -4
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.test.tsx +16 -57
- package/templates/runtime/react/app-shell/toolcraft-source-asset-context.tsx +75 -434
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.test.ts +194 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-owner.ts +227 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-provider-ownership.test.tsx +243 -0
- package/templates/runtime/react/app-shell/toolcraft-source-asset-test-support.ts +51 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.test.ts +138 -0
- package/templates/runtime/react/app-shell/toolcraft-unavailable-resource-proof.ts +378 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.footer-actions.test.tsx +7 -12
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +17 -83
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +42 -84
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +62 -0
- package/templates/runtime/react/panel-host/panel-host-runtime-placement.test.tsx +30 -0
- package/templates/runtime/react/panel-host/panel-host.tsx +4 -0
- package/templates/runtime/scene/scene-bounds.ts +1 -2
- package/templates/runtime/schema/canvas-render-scale.ts +62 -0
- package/templates/runtime/schema/controls-panel-section-id.test.ts +1 -1
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +3 -3
- package/templates/runtime/schema/define-toolcraft.setup-background.test.ts +1 -1
- package/templates/runtime/schema/define-toolcraft.setup-render-scale-timeline.test.ts +71 -3
- package/templates/runtime/schema/define-toolcraft.ts +1 -1
- package/templates/runtime/schema/schema-resolvers.ts +0 -56
- package/templates/runtime/schema/types.ts +4 -4
- package/templates/runtime/state/canvas-background-state.ts +6 -0
- package/templates/runtime/testing/performance-render-plan-integration.test.ts +64 -0
- package/templates/runtime/testing/performance-renderer-pipeline-validation.ts +18 -1
- package/templates/starter/AGENTS.md +8 -7
- package/templates/starter/NOTICE.md +6 -0
- package/templates/starter/docs/toolcraft/README.md +2 -1
- package/templates/starter/docs/toolcraft/acceptance-testing.md +8 -6
- package/templates/starter/docs/toolcraft/agent-worklog.md +3 -3
- package/templates/starter/docs/toolcraft/assembly-workflow.md +4 -3
- package/templates/starter/docs/toolcraft/core/media-upload.md +2 -2
- package/templates/starter/docs/toolcraft/core/performance.md +14 -3
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +3 -1
- package/templates/starter/docs/toolcraft/core/setup-export.md +16 -12
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +4 -4
- package/templates/starter/docs/toolcraft/performance.md +20 -6
- package/templates/starter/docs/toolcraft/renderer-technique.md +1 -1
- package/templates/starter/docs/toolcraft/schema-reference.md +2 -6
- package/templates/starter/docs/toolcraft/workflow.md +7 -2
- package/templates/starter/e2e/app-browser-control-coverage.spec.ts +33 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +43 -1
- package/templates/starter/e2e/app-browser-render-scale-evidence.spec.ts +60 -6
- package/templates/starter/e2e/app-browser-render-scale-requirements.spec.ts +77 -1
- package/templates/starter/e2e/app-browser-runtime-provenance.spec.ts +8 -0
- package/templates/starter/e2e/app-browser-runtime-reporter.spec.ts +35 -0
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +4 -1
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +0 -1
- package/templates/starter/e2e/app-browser-shell.spec.ts +13 -5
- package/templates/starter/e2e/app-performance-path-adapters.ts +8 -1
- package/templates/starter/e2e/app-performance.spec.ts +16 -9
- package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +9 -330
- package/templates/starter/e2e/browser-infinity-canvas-unavailable-image-evidence.ts +370 -0
- package/templates/starter/e2e/browser-media-export-evidence.spec.ts +77 -0
- package/templates/starter/e2e/browser-media-export-evidence.ts +208 -0
- package/templates/starter/e2e/browser-render-scale-evidence.ts +37 -29
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +4 -1
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +43 -9
- package/templates/starter/e2e/browser-standard-timeline-evidence.ts +106 -0
- package/templates/starter/e2e/decoded-pixel-observation.spec.ts +74 -0
- package/templates/starter/e2e/decoded-pixel-observation.ts +227 -0
- package/templates/starter/e2e/export-artifact-helpers.ts +206 -25
- package/templates/starter/e2e/image-artifact-inspection.spec.ts +41 -0
- package/templates/starter/e2e/image-artifact-inspection.ts +99 -0
- package/templates/starter/e2e/performance-canvas-helpers.ts +22 -21
- package/templates/starter/e2e/performance-canvas-quality-guard.spec.ts +312 -0
- package/templates/starter/e2e/performance-canvas-quality-guard.ts +196 -0
- package/templates/starter/e2e/performance-canvas-quality-observer.ts +351 -0
- package/templates/starter/e2e/performance-control-layout-helpers.ts +2 -2
- package/templates/starter/e2e/performance-path-adapter-contract.ts +4 -4
- package/templates/starter/e2e/performance-path-helpers.spec.ts +203 -70
- package/templates/starter/e2e/performance-path-helpers.ts +210 -91
- package/templates/starter/e2e/performance-pipeline-evidence-continuity.spec.ts +76 -0
- package/templates/starter/e2e/performance-pipeline-evidence-test-fixtures.ts +11 -2
- package/templates/starter/e2e/performance-pipeline-invariants.ts +47 -4
- package/templates/starter/e2e/performance-render-scale-runner.spec.ts +140 -38
- package/templates/starter/e2e/video-artifact-inspection.spec.ts +64 -0
- package/templates/starter/e2e/video-artifact-inspection.ts +281 -0
- package/templates/starter/gitignore +1 -0
- package/templates/starter/package.json +1 -0
- package/templates/starter/scripts/check-toolcraft-docs.mjs +17 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-authority.test.mjs +60 -0
- package/templates/starter/scripts/toolcraft-delivery-plan-errors.test.mjs +7 -2
- package/templates/starter/scripts/toolcraft-delivery-plan.mjs +7 -3
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +24 -2
- package/templates/starter/scripts/toolcraft-product-boundary.mjs +12 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +46 -0
- package/templates/starter/scripts/toolcraft-product-evidence-boundary.test.mjs +85 -20
- package/templates/starter/scripts/toolcraft-product-evidence-import-policy.mjs +43 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +168 -0
- package/templates/starter/scripts/toolcraft-typescript-analysis.d.mts +73 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade-test-helpers.mjs +318 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +155 -206
- package/templates/starter/scripts/toolcraft-verification-inventory.mjs +1 -0
- package/templates/starter/scripts/toolcraft-verification-receipt.test.mjs +51 -0
- package/templates/starter/scripts/toolcraft-vite-env-activation.test.mjs +128 -59
- package/templates/starter/src/app/acceptance/export-artifact-coverage.ts +113 -0
- package/templates/starter/src/app/acceptance/output-background-rules.ts +1 -1
- package/templates/starter/src/app/acceptance/output-export.ts +13 -2
- package/templates/starter/src/app/acceptance/types.ts +7 -0
- package/templates/starter/src/app/acceptance/validate-coverage.ts +2 -1
- package/templates/starter/src/app/starter-acceptance.export-artifact.test.ts +131 -0
- package/templates/starter/src/app/starter-acceptance.keyframes.test.ts +14 -4
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +42 -1
- package/templates/starter/src/app/starter-acceptance.ts +2 -0
- package/templates/starter/src/app/starter-performance-test-utils.ts +103 -0
- package/templates/starter/src/app/starter-performance.gates.test.ts +231 -278
- package/templates/starter/src/app/starter-performance.lifecycle.test.ts +261 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +2 -0
- package/templates/starter/src/routes/index.tsx +1 -0
- package/templates/runtime/export/export.ts +0 -166
|
@@ -18,14 +18,6 @@ export const defaultToolcraftCanvasSize = {
|
|
|
18
18
|
width: 1920,
|
|
19
19
|
} satisfies ToolcraftCanvasSize;
|
|
20
20
|
|
|
21
|
-
const defaultCanvasRenderScale = {
|
|
22
|
-
defaultValue: 2,
|
|
23
|
-
enabled: false,
|
|
24
|
-
max: 2,
|
|
25
|
-
min: 1,
|
|
26
|
-
step: 0.25,
|
|
27
|
-
} satisfies ResolvedToolcraftAppSchema["canvas"]["renderScale"];
|
|
28
|
-
|
|
29
21
|
export function resolveToolcraftCanvasSizing(
|
|
30
22
|
canvas: ToolcraftAppSchema["canvas"],
|
|
31
23
|
): ToolcraftCanvasSizingSchema {
|
|
@@ -44,54 +36,6 @@ export function resolveToolcraftCanvasSizing(
|
|
|
44
36
|
return { mode: "intrinsic-media" };
|
|
45
37
|
}
|
|
46
38
|
|
|
47
|
-
function clampCanvasRenderScale(value: number | undefined, fallback: number): number {
|
|
48
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
49
|
-
return fallback;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
return Math.max(1, Math.min(2, value));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function resolveToolcraftCanvasRenderScale(
|
|
56
|
-
renderScale: ToolcraftAppSchema["canvas"]["renderScale"],
|
|
57
|
-
): ResolvedToolcraftAppSchema["canvas"]["renderScale"] {
|
|
58
|
-
if (renderScale === true) {
|
|
59
|
-
return {
|
|
60
|
-
...defaultCanvasRenderScale,
|
|
61
|
-
enabled: true,
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!renderScale) {
|
|
66
|
-
return defaultCanvasRenderScale;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const min = clampCanvasRenderScale(renderScale.min, defaultCanvasRenderScale.min);
|
|
70
|
-
const max = Math.max(
|
|
71
|
-
min,
|
|
72
|
-
clampCanvasRenderScale(renderScale.max, defaultCanvasRenderScale.max),
|
|
73
|
-
);
|
|
74
|
-
const step =
|
|
75
|
-
typeof renderScale.step === "number" && Number.isFinite(renderScale.step)
|
|
76
|
-
? Math.max(0.01, Math.min(1, renderScale.step))
|
|
77
|
-
: defaultCanvasRenderScale.step;
|
|
78
|
-
const defaultValue = Math.max(
|
|
79
|
-
min,
|
|
80
|
-
Math.min(
|
|
81
|
-
max,
|
|
82
|
-
clampCanvasRenderScale(renderScale.defaultValue, defaultCanvasRenderScale.defaultValue),
|
|
83
|
-
),
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
defaultValue,
|
|
88
|
-
enabled: renderScale.enabled ?? true,
|
|
89
|
-
max,
|
|
90
|
-
min,
|
|
91
|
-
step,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
39
|
export function resolveToolcraftExport(
|
|
96
40
|
exportSchema: ToolcraftAppSchema["export"],
|
|
97
41
|
): ResolvedToolcraftAppSchema["export"] {
|
|
@@ -40,10 +40,10 @@ export type ToolcraftCanvasSizingSchema =
|
|
|
40
40
|
export type ToolcraftCanvasRenderScaleSchema =
|
|
41
41
|
| boolean
|
|
42
42
|
| {
|
|
43
|
-
defaultValue?:
|
|
44
|
-
enabled?:
|
|
45
|
-
max?:
|
|
46
|
-
min?:
|
|
43
|
+
defaultValue?: never;
|
|
44
|
+
enabled?: never;
|
|
45
|
+
max?: never;
|
|
46
|
+
min?: never;
|
|
47
47
|
step?: number;
|
|
48
48
|
};
|
|
49
49
|
|
|
@@ -64,6 +64,12 @@ export function getToolcraftInfiniteCanvasBackgroundColor(
|
|
|
64
64
|
return undefined;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
return getToolcraftRuntimeBackgroundColor(state);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function getToolcraftRuntimeBackgroundColor(
|
|
71
|
+
state: ToolcraftState,
|
|
72
|
+
): string | undefined {
|
|
67
73
|
const background = getToolcraftRuntimeSetupBackgroundControls(state.schema);
|
|
68
74
|
const value = background
|
|
69
75
|
? state.values[background.color.target] ?? background.color.defaultValue
|
|
@@ -34,6 +34,70 @@ describe("Toolcraft render plan integration", () => {
|
|
|
34
34
|
);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
+
it("allows off-main retina rasterization to preserve exact backing during viewport zoom", () => {
|
|
38
|
+
const pass = createPass({
|
|
39
|
+
cacheKey: undefined,
|
|
40
|
+
cost: {
|
|
41
|
+
dimensions: ["output-units"],
|
|
42
|
+
frequency: "interaction",
|
|
43
|
+
relationship: "linear",
|
|
44
|
+
},
|
|
45
|
+
id: "viewport-raster",
|
|
46
|
+
inputs: ["canvas.viewport.zoom"],
|
|
47
|
+
invalidatedBy: ["canvas.viewport.zoom"],
|
|
48
|
+
kind: "rasterize",
|
|
49
|
+
lifecycle: { cache: "none", resourceScope: "interaction" },
|
|
50
|
+
quality: "retina",
|
|
51
|
+
runsOn: "worker",
|
|
52
|
+
});
|
|
53
|
+
const baseConfig = createEnvelopeConfig({ pass });
|
|
54
|
+
const rendererPipeline = {
|
|
55
|
+
...baseConfig.rendererPipeline!,
|
|
56
|
+
interactionInvalidation: [
|
|
57
|
+
{
|
|
58
|
+
interaction: "viewport-zoom" as const,
|
|
59
|
+
invalidates: [pass.id],
|
|
60
|
+
targets: ["canvas.viewport.zoom"],
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
const renderScaleSchema = {
|
|
65
|
+
...testSchema,
|
|
66
|
+
canvas: {
|
|
67
|
+
...testSchema.canvas,
|
|
68
|
+
renderScale: { ...testSchema.canvas.renderScale, enabled: true },
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
const errors = validateToolcraftPerformanceCoverage(
|
|
72
|
+
renderScaleSchema,
|
|
73
|
+
{ ...baseConfig, rendererPipeline },
|
|
74
|
+
TOOLCRAFT_FUNCTIONAL_PERFORMANCE_COVERAGE_POLICY,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
expect(errors).not.toContainEqual(
|
|
78
|
+
expect.stringContaining(
|
|
79
|
+
'viewport-zoom must not invalidate expensive pass "viewport-raster"',
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
expect(
|
|
83
|
+
validateToolcraftPerformanceCoverage(
|
|
84
|
+
renderScaleSchema,
|
|
85
|
+
{
|
|
86
|
+
...baseConfig,
|
|
87
|
+
rendererPipeline: {
|
|
88
|
+
...rendererPipeline,
|
|
89
|
+
passes: [{ ...pass, quality: "full" }],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
TOOLCRAFT_FUNCTIONAL_PERFORMANCE_COVERAGE_POLICY,
|
|
93
|
+
),
|
|
94
|
+
).toContainEqual(
|
|
95
|
+
expect.stringContaining(
|
|
96
|
+
'viewport-zoom must not invalidate expensive pass "viewport-raster"',
|
|
97
|
+
),
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
37
101
|
it.each(["memoized", "retained-resource"] as const)(
|
|
38
102
|
"requires cacheKey for a composite pass with %s cache",
|
|
39
103
|
(cache) => {
|
|
@@ -106,6 +106,22 @@ function hasPipelineReference(value: string): boolean {
|
|
|
106
106
|
return value.trim().length > 0 && !vaguePipelineReferencePattern.test(value.trim());
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
+
function isRetinaViewportZoomRaster(
|
|
110
|
+
schema: ResolvedToolcraftAppSchema,
|
|
111
|
+
interaction: ToolcraftPipelineInteraction,
|
|
112
|
+
pass: ToolcraftRenderPass,
|
|
113
|
+
): boolean {
|
|
114
|
+
return (
|
|
115
|
+
interaction === "viewport-zoom" &&
|
|
116
|
+
schema.canvas.renderScale.enabled &&
|
|
117
|
+
pass.kind === "rasterize" &&
|
|
118
|
+
pass.quality === "retina" &&
|
|
119
|
+
(pass.runsOn === "worker" ||
|
|
120
|
+
pass.runsOn === "gpu" ||
|
|
121
|
+
pass.runsOn === "worker-or-gpu")
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
109
125
|
function getPipelineReferenceErrors(
|
|
110
126
|
passId: string,
|
|
111
127
|
field: string,
|
|
@@ -317,7 +333,8 @@ function getRendererPipelineErrorsFromParsedPipeline(
|
|
|
317
333
|
|
|
318
334
|
if (
|
|
319
335
|
highFrequencyViewportInteractions.has(invalidation.interaction) &&
|
|
320
|
-
expensiveRenderPassKinds.has(pass.kind)
|
|
336
|
+
expensiveRenderPassKinds.has(pass.kind) &&
|
|
337
|
+
!isRetinaViewportZoomRaster(schema, invalidation.interaction, pass)
|
|
321
338
|
) {
|
|
322
339
|
errors.push(
|
|
323
340
|
`rendererPipeline ${invalidation.interaction} must not invalidate expensive pass "${passId}" (${pass.kind}). Move viewport work to transforms/uniforms or explain it through a cheaper pass.`,
|
|
@@ -33,7 +33,7 @@ Process matching routes sequentially within the current phase and skip repeated
|
|
|
33
33
|
13. Generated apps follow the mandatory runtime Setup, Infinity canvas/finite canvas sizing, render scale, Timeline switch, Background, Image Export, Video Export, and sticky action rules in `docs/toolcraft/core/setup-export.md`. Do not duplicate or reinterpret those controls in app-authored sections.
|
|
34
34
|
14. Media uploads, image/file mode, source images, multi-upload sorting, default assets, and image transform actions follow `docs/toolcraft/core/media-upload.md`.
|
|
35
35
|
15. Keep `docs/toolcraft/agent-worklog.md` current with a decision trail, product decisions, explicit reference inputs, evidence, verification, and risks. Reference-runtime-clone apps also declare `referenceStudy` plus `referenceFeatureInventory` so every inspected reference feature has feature-level behavior evidence and maps to Toolcraft implementation and acceptance coverage.
|
|
36
|
-
16. Prove every visible entity through acceptance, browser, and performance coverage. Browser acceptance and performance pass only when protected helpers emit matching runtime evidence after successful assertions; source-code spelling and acceptance prose are not outcome authority. Declare typed conditional-visibility and background-output coverage, then use their fixed protected browser recipes. Raster products with `canvas.renderScale` declare `renderScaleCoverage` for interaction and steady state, plus playback when timeline is enabled, and prove real backing pixels with `canvas-render-scale-backing`; clamping quality is a functional failure without measured performance. Generic acceptance outcomes prove command side effects only; use the fixed media, persistence, viewport, compound-control, layer, and timeline semantic recipes for specialized evidence.
|
|
36
|
+
16. Prove every visible entity through acceptance, browser, and performance coverage. Browser acceptance and performance pass only when protected helpers emit matching runtime evidence after successful assertions; source-code spelling and acceptance prose are not outcome authority. Declare typed conditional-visibility and background-output coverage, then use their fixed protected browser recipes. Raster products with `canvas.renderScale` declare `renderScaleCoverage` for interaction and steady state, plus playback when timeline is enabled, and prove real backing pixels with `canvas-render-scale-backing`; clamping quality is a functional failure without measured performance. Every measured path in a render-scale-enabled raster product proves actual CSS × devicePixelRatio × 2 backing after each measured phase. Generic acceptance outcomes prove command side effects only; use the fixed media, persistence, viewport, compound-control, layer, and timeline semantic recipes for specialized evidence.
|
|
37
37
|
17. Performance planning follows one sequence: reachable controls and inputs; workload dimensions and enforced boundaries; pass cost, frequency, lifecycle, and invalidation; render-plan assessment and protected kernel benchmark when required; derived paths and combined fixtures; targeted functional/browser development checks; lifecycle-appropriate delivery proof. Keep `src/app/app-verification-impact.json` complete so later functional changes derive exact verification scope. Only exact request authority may create a measured targeted performance iteration. Details live in `docs/toolcraft/core/performance.md` and `docs/toolcraft/performance.md`.
|
|
38
38
|
18. Custom renderer apps compile one canonical `rendererPipelineRegistration`, supply it through `ToolcraftAppComposition`, reuse that registration as `rendererPipeline` in performance assessment, and derive paths and fixtures from it. The neutral starter has no registration, runtime provider, or fixture adapters.
|
|
39
39
|
19. Classify each coherent user-visible delivery batch with a verification tier before editing. Steering and fixes inside the same request stay in that batch. Use targeted checks for development feedback, then run the protected delivery gate once when the batch is ready.
|
|
@@ -119,11 +119,12 @@ These ids mirror `TOOLCRAFT_DECISION_CONTRACT` in `@/toolcraft/runtime`. Keep th
|
|
|
119
119
|
|
|
120
120
|
- Use `defineToolcraft` from `@/toolcraft/runtime`.
|
|
121
121
|
- Export an `appComposition` satisfying `ToolcraftAppComposition` from `src/app/app-composition.tsx`.
|
|
122
|
-
- Keep product composition limited to `schema`, `canvasContent`, `controlRenderers`, `modelPresentation`, `onPanelAction`, `renderDefaultCanvasMedia`, and optional `rendererPipelineRegistration`; host `className` and `style` are not product extension points.
|
|
122
|
+
- Keep product composition limited to `schema`, `canvasContent`, `controlRenderers`, `exportRenderer`, `modelPresentation`, `onPanelAction`, `renderDefaultCanvasMedia`, and optional `rendererPipelineRegistration`; host `className` and `style` are not product extension points.
|
|
123
123
|
- Custom renderers use one compiled `rendererPipelineRegistration` as the canonical declaration for runtime execution and new-envelope performance assessment. Product code receives only the disposal-free pipeline client through hooks and panel action context.
|
|
124
124
|
- Do not import `ToolcraftApp`, low-level runtime surfaces, or built-in controls into product modules. The signed host renders the shell; product modules use schema controls and supported composition fields.
|
|
125
125
|
- Use `renderDefaultCanvasMedia={false}` when a custom renderer replaces generic image/file preview. This flag does not suppress runtime model layers; use typed `modelPresentation` custom mode with checked consumers for declared model targets.
|
|
126
|
-
- Use `ToolcraftApp onPanelAction` for sticky footer product actions such as Generate, Apply,
|
|
126
|
+
- Use `ToolcraftApp onPanelAction` for non-export sticky footer product actions such as Generate, Apply, Copy, or Download. Typed `export-image` and `export-video` actions are executed by the runtime from the shared `ToolcraftAppComposition.exportRenderer`.
|
|
127
|
+
- Product export renderers draw one deterministic scene-coordinate frame and return/await their real work. Product modules never allocate export canvases, choose encoders, encode blobs, create download URLs, or duplicate image/video composition.
|
|
127
128
|
- Keep final app behavior in the schema and runtime command bus, not in isolated local control state.
|
|
128
129
|
- For animated products, write an Animation Intent Inventory before coding: use top playback timeline for product transport, keyframes timeline for editable property animation, and no timeline only for explicitly autonomous decorative output with no video export. Any app with `Export Video` must enable the top Toolcraft timeline.
|
|
129
130
|
- For keyframes timeline apps, renderers read keyframed settings through Toolcraft evaluated-value helpers/hooks. Do not parse timeline `valueLabel` strings or read raw `state.values` for keyframed targets.
|
|
@@ -172,7 +173,7 @@ Do not rerun `pnpm install` after every edit. Run it after fresh export, depende
|
|
|
172
173
|
|
|
173
174
|
Do not run the full browser performance suite for Tier 0-2 edits.
|
|
174
175
|
|
|
175
|
-
The automatic lifecycle is sequential. First product delivery uses bare `pnpm verify:delivery` for complete product contracts, one production build, full functional acceptance, and zero measured performance. Later delivery is functional-targeted: it compares the immediately previous and current semantic functional proof models and derives exact direct-owner, domain, and affected-unit-graph proof.
|
|
176
|
+
The automatic lifecycle is sequential. First product delivery uses bare `pnpm verify:delivery` for complete product contracts, one production build, full functional acceptance, and zero measured performance. Later delivery is functional-targeted: it compares the immediately previous and current semantic functional proof models and derives exact direct-owner, domain, and affected-unit-graph proof. Classifier output establishes complaint authority only, never path localization. For a localized performance complaint, select affected canonical paths and run one targeted iteration without clarification. When localization remains unresolved, regardless of whether classification is high-confidence `performance-iteration` or `needs-agent-judgment`, ask one user-facing question naming visible operations and offering targeted diagnosis or a complete review; unresolved localization creates neither performance-iteration intent nor canonical path authority, and internal path IDs are never user choices. A broad or unlocalizable problem may justify recommending the complete review in that single choice, but the user still chooses; an explicit complete-review request runs `pnpm verify:perf` directly. The canonical selection and evidence rules live in `docs/toolcraft/workflow.md`, `docs/toolcraft/acceptance-testing.md`, and `docs/toolcraft/performance.md`; do not duplicate their algorithm here.
|
|
176
177
|
|
|
177
178
|
Feature loops after the first working version run only the smallest focused functional and browser checks while implementation is changing, then one bare `verify:delivery` at the coherent boundary. Do not rerun aggregate, export, or performance matrices after every edit. An unchanged `sourceHash` uses the protected fast path and does not recollect semantic proof inputs.
|
|
178
179
|
|
|
@@ -187,7 +188,7 @@ pnpm verify:delivery
|
|
|
187
188
|
pnpm dev
|
|
188
189
|
```
|
|
189
190
|
|
|
190
|
-
The protected runner selects first-delivery functional proof, later `functional-targeted` ownership-derived proof, or one
|
|
191
|
+
The protected runner selects first-delivery functional proof, later `functional-targeted` ownership-derived proof, or one localized-or-clarified targeted performance iteration from protected state. Classifier output alone never supplies path localization; unresolved localization creates neither performance-iteration intent nor canonical path authority regardless of classifier result. `pnpm verify:perf` is the separate operator/CI full-audit command; run it only after an explicit user request or accepted agent offer, never as an inferred continuation of a complaint.
|
|
191
192
|
|
|
192
193
|
Use `pnpm install` before this final gate when the folder is fresh or dependencies changed.
|
|
193
194
|
|
|
@@ -207,9 +208,9 @@ The app is complete only when:
|
|
|
207
208
|
- sticky footer export actions operate on final product output at `state.canvas.size`;
|
|
208
209
|
- every product exposes Export PNG; products whose requested delivery includes animation also expose Export Video;
|
|
209
210
|
- PNG export uses the background controls normalized into runtime Setup: `Background` beside `Infinity canvas`, then `Background color`; live preview hides product background when Background is off, and video keeps background;
|
|
210
|
-
- every PNG export includes `Image Export` format/resolution `select` controls
|
|
211
|
+
- every PNG export includes `Image Export` format/resolution `select` controls; runtime resolves the selected settings and exact output size;
|
|
211
212
|
- products with both PNG and video export place `Image Export` immediately before `Video Export`;
|
|
212
|
-
-
|
|
213
|
+
- one shared `exportRenderer` draws product pixels for both image and video; runtime owns selected settings, scene crop, background, runtime media/model compositing, canvas allocation, encoding, download, progress, and typed errors;
|
|
213
214
|
- layers are absent for single-layer apps and fully working when enabled;
|
|
214
215
|
- timeline is absent, playback, keyframes, or custom reference timeline according to product behavior;
|
|
215
216
|
- performance checks cover workload and responsiveness for all relevant controls;
|
|
@@ -6,3 +6,9 @@ starter, UI component, documentation, and template source code.
|
|
|
6
6
|
Use of that Toolcraft code is governed by the MIT License in `LICENSE.md`.
|
|
7
7
|
Product-specific design, content, configuration, and application code that you
|
|
8
8
|
create remain yours.
|
|
9
|
+
|
|
10
|
+
## Mediabunny
|
|
11
|
+
|
|
12
|
+
Video export uses Mediabunny 1.52.2, Copyright © 2026 Vanilagy,
|
|
13
|
+
licensed under the Mozilla Public License 2.0 (MPL-2.0).
|
|
14
|
+
Source: https://github.com/Vanilagy/mediabunny
|
|
@@ -40,7 +40,8 @@ Use focused tests while a coherent user-visible delivery batch is changing. Stee
|
|
|
40
40
|
|
|
41
41
|
- **First product delivery:** bare `pnpm verify:delivery` proves complete product contracts, performs one production build, runs full functional acceptance, and runs no measured performance. It preserves any independent performance baseline.
|
|
42
42
|
- **Later functional delivery:** the same bare command compares with the immediately previous successful delivery and derives exact ownership-required proof.
|
|
43
|
-
- **
|
|
43
|
+
- **Localized or clarified targeted work:** classifier output establishes complaint authority only and never path localization. Only a localized complaint or a post-clarification targeted choice records an exact request quote and canonical affected path IDs in the worklog, then one bare delivery runs one targeted iteration and returns the verified app for evaluation. Unresolved localization creates neither performance-iteration intent nor canonical path authority regardless of classifier result.
|
|
44
|
+
- **Adaptive complaint route:** a localized complaint lets the agent choose affected paths without a question; an ambiguous complaint gets one visible-operation choice between targeted diagnosis and a complete performance review; a broad problem may receive the same recommendation, while only an explicit request or accepted offer authorizes the full review.
|
|
44
45
|
- **Full audit:** only an explicit operator request or accepted offer authorizes `pnpm verify:perf`, which performs one fresh build and the complete maximum-fixture performance matrix.
|
|
45
46
|
|
|
46
47
|
Use the current AI agent's controlled browser for targeted diagnosis and visual checks.
|
|
@@ -82,6 +82,8 @@ The `e2e/app-browser-*` prefix is reserved for signed framework specs.
|
|
|
82
82
|
|
|
83
83
|
Every runtime production module/resource has a direct owner in `src/app/app-verification-impact.json`; proof and test paths cannot own them. Each browser file owns one acceptance domain (the first ID segment). Later delivery compares semantic models and selects changed contracts, owners/domains, and product-unit tests—not filenames or reverse imports. Additive owner deltas select only new IDs; other deltas retain affected IDs.
|
|
84
84
|
|
|
85
|
+
Classifier output establishes complaint authority only; unresolved localization creates no intent/path regardless of result. Only localized/clarified work starts an iteration.
|
|
86
|
+
|
|
85
87
|
Contract docs are signed except product-owned `agent-worklog.md` and optional `workflow-observation.md`; only the observation stays outside `sourceHash`.
|
|
86
88
|
|
|
87
89
|
Framework meta-tests are product-invariant: their synthetic validator cases use protected neutral contract fixtures, never the editable app schema, product acceptance rows, transfer intent, or section inventory. Put exact product targets, defaults, option values, and product-specific expectations in separate app-owned tests. The product gates still read `app-schema.ts`, `app-acceptance-data.ts`, product test names, worklog evidence, and browser scenarios dynamically.
|
|
@@ -94,13 +96,13 @@ Slider and range slider rows must prove live behavior. Browser tests should drag
|
|
|
94
96
|
|
|
95
97
|
## Infinity Canvas Coverage
|
|
96
98
|
|
|
97
|
-
Every editable-output
|
|
99
|
+
Every editable-output app proves `infinityCanvasCoverage` mode/restoration. With Background, proof changes its color, verifies the infinite viewport, turns it off to restore finite mode/disable Infinity, then on without enabling Infinity. Image/video proof decodes scene-bounds output from `sceneBoundsProvider`; runtime video unions exact bounds from every scheduled frame state. Fixed recipes cover excluded content and exact empty, unavailable, and oversized failures. See `core/setup-export.md`.
|
|
98
100
|
|
|
99
101
|
## Render Scale Coverage
|
|
100
102
|
|
|
101
|
-
|
|
103
|
+
For a raster product with render scale, add one `canvas.renderScale` browser row: `renderScaleCoverage: { kind: "selected-backing-pixels", states: ["interaction", "steady"] }`; timeline adds `"playback"`.
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
Run `expectToolcraftCanvasRenderScaleEvidence` per state. CSS size stays fixed and backing must equal `CSS × devicePixelRatio × selected scale` within one pixel before `canvas-render-scale-backing`; mismatch fails. Every measured path in that product proves exact `CSS × devicePixelRatio × 2` after each phase.
|
|
104
106
|
|
|
105
107
|
Default local persistence requires one runtime row with `evidence: "persistence-state"`, `persistenceCoverage: "reload"`, and `persistenceSlices` equal to the resolved plan. Browser proof changes each slice, waits for status `success`, reloads, then verifies restored state and real output before evidence. Settings import/export is not reload proof.
|
|
106
108
|
|
|
@@ -230,9 +232,9 @@ Export-content proof is distinct from export mechanics: content inspects selecte
|
|
|
230
232
|
|
|
231
233
|
Every app with `Export PNG` must exercise the separate `Image Export` section: choose at least two `export.image.format` values, choose at least two `export.image.resolution` values, export the image, and decode the result to prove file type and actual pixel dimensions changed. Animated apps with both `Export PNG` and `Export Video` still need this image-export coverage; `Video Export` does not replace it.
|
|
232
234
|
|
|
233
|
-
|
|
235
|
+
Runtime Export acceptance must prove the sticky footer top accent indicator advances through real render/encode/download work and hides only after the artifact settles. Async non-export Download, Copy, Generate, or Apply acceptance must prove the indicator is visible while the returned `onPanelAction` Promise is pending, advances when `reportProgress(0..1)` is called, and hides after it settles.
|
|
234
236
|
|
|
235
|
-
Animated app acceptance
|
|
237
|
+
Animated app acceptance exercises two video formats and resolutions. It proves real bytes, dimensions, actual MIME/container or typed capability failure, timeline duration, 30 FPS timestamps/durations from actual encoded packet metadata, decoded product motion, current even-safe sizing, and aspect-preserving 4K inside 3840x2160. Renderer/encoder/muxer errors reject; `blobSize`, metadata alone, assumed FPS, synthetic frame counts, or substituted expectations are invalid. Animated output requires distinct decoded frame hashes.
|
|
236
238
|
|
|
237
239
|
Footer action acceptance must not include Reset. Reset is already available in the controls panel header and uses schema `defaultValue`; duplicating it in sticky `panelActions` fails acceptance.
|
|
238
240
|
|
|
@@ -240,7 +242,7 @@ Local `actions` acceptance must click every visible action and prove the nearby
|
|
|
240
242
|
|
|
241
243
|
`collectionActions` acceptance must click plus and minus in the real panel, prove the runtime target array length changes, prove `minItems` prevents invalid removal, prove `recommendedMaxItems` is not a hidden hard limit, and prove preview/export consumes the changed item list.
|
|
242
244
|
|
|
243
|
-
|
|
245
|
+
Image export proves background changes in preview/artifact/infinite viewport; Background off restores finite mode, disables Infinity, hides bounded preview background, and makes PNG transparent while JPEG/video stay opaque. Restoring it enables Infinity availability without entering that mode. Protected proof decodes real type, selected dimensions, product bounds/pixels, and pixel hash; bytes or dimensions alone are insufficient.
|
|
244
246
|
|
|
245
247
|
Hard acceptance semantics are typed, not inferred from English prose. Every `visibleWhen` acceptance row declares `visibilityCoverage` for both `hidden` and `visible`; the protected conditional-visibility recipe must remove the dependent target from the rendered panel and restore it through the same target-scoped gating control. The `export.includeBackground` row declares `backgroundOutputCoverage` for preview exclusion and transparent image alpha, plus preserved video background when the schema exposes video export. Its protected recipe verifies the preview transition, decodes a non-empty image artifact and checks background alpha, and inspects video background behavior when applicable. `expectedObservable` and `userAction` remain human-readable context and may use any language; matching words such as “hidden”, “PNG”, or “video” never satisfy these requirements by themselves.
|
|
246
248
|
|
|
@@ -12,13 +12,13 @@ The neutral starter has no product renderer, timeline, layers, export behavior,
|
|
|
12
12
|
|
|
13
13
|
Keep this worklog human-shaped. For the first product delivery, record the request, decisions, state/output mapping, reference evidence, rejected alternatives, and known risks; one bare `pnpm verify:delivery` derives complete contract proof, one build, full functional acceptance, and no measured performance. For later `functional-targeted` delivery, record only the new intent and decisions; the same bare command derives exact ownership-required proof from protected state.
|
|
14
14
|
|
|
15
|
-
A performance complaint adds
|
|
15
|
+
Classifier output establishes complaint authority only and never path localization. A localized performance complaint adds the domain authority below, then one bare `pnpm verify:delivery` runs one targeted iteration. If localization remains unresolved regardless of classifier result, ask one user-facing question naming visible operations and offering targeted diagnosis or a complete review; record neither `performance-iteration` intent nor canonical path authority until the answer supplies exact localization evidence. Never ask the user to choose internal path IDs. A broad or honestly unlocalizable problem may present that single choice with a recommendation for complete review, but the user still chooses. A direct complete-review request needs no further clarification. The full audit remains separate and requires an explicit operator request or accepted offer before `pnpm verify:perf` may run. Protected receipts own changed files, plans, checks, reports, measurements, and pass/fail evidence.
|
|
16
16
|
|
|
17
17
|
When `canvas.renderScale` is enabled, record the renderer decision to preserve selected backing quality and map it to functional `renderScaleCoverage` for interaction and steady state, plus playback when timeline is enabled. The worklog may name the protected `canvas-render-scale-backing` recipe, but it cannot claim its evidence or turn a quality failure into performance authority.
|
|
18
18
|
|
|
19
19
|
## Performance Iteration Entry Contract
|
|
20
20
|
|
|
21
|
-
For high-confidence ordinary work, record `Performance intent: ordinary-product-work`. For a performance complaint or
|
|
21
|
+
For high-confidence ordinary work, record `Performance intent: ordinary-product-work`. For unresolved localization, whether classification returned high-confidence `performance-iteration` or `needs-agent-judgment`, record the unresolved visible operation but no `Performance intent: performance-iteration` field or `Performance paths` until the user's one clarification provides exact localization. For a localized performance complaint or post-clarification targeted choice, record exactly these domain fields in the latest iteration:
|
|
22
22
|
|
|
23
23
|
```md
|
|
24
24
|
- Performance intent: performance-iteration
|
|
@@ -27,7 +27,7 @@ For high-confidence ordinary work, record `Performance intent: ordinary-product-
|
|
|
27
27
|
- Verification: One bare `pnpm verify:delivery` will derive and run the protected proof.
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The quoted evidence must be an exact nontrivial raw substring of `Request` with identical whitespace and Unicode code units. `Performance paths` must be a non-empty unique JSON array of canonical path IDs. Do not record command arguments, changed-file inventory, executed checks, reports, or measurements; the protected planner and receipt own that machine evidence.
|
|
30
|
+
The quoted evidence must be an exact nontrivial raw substring of `Request` with identical whitespace and Unicode code units. `Performance paths` must be a non-empty unique JSON array of canonical path IDs. Do not record command arguments, changed-file inventory, executed checks, reports, or measurements; the protected planner and receipt own that machine evidence. Each localized complaint or post-clarification targeted choice authorizes one bounded iteration; after it passes, return the app and wait for user evaluation. Classifier output or complaint evidence alone never supplies path localization or authorizes full certification. The separate operator command is permitted only after the user explicitly requests a complete audit or explicitly accepts the agent's offer; the user does not need to name the command.
|
|
31
31
|
|
|
32
32
|
## Decision Trail
|
|
33
33
|
|
|
@@ -25,7 +25,7 @@ export const appComposition = {
|
|
|
25
25
|
} satisfies ToolcraftAppComposition;
|
|
26
26
|
```
|
|
27
27
|
|
|
28
|
-
Edit `src/app/app-composition.tsx`, not the signed route. Product composition may provide only `schema`, `canvasContent`, `controlRenderers`, `modelPresentation`, `onPanelAction`, `renderDefaultCanvasMedia`, and optional `rendererPipelineRegistration`; the protected route owns `className` and other host layout. Model products default to `modelPresentation: { mode: "runtime" }`. Custom presentation declares checked consumers and suppresses only their model targets; `renderDefaultCanvasMedia={false}` affects generic image/file preview, not runtime models. Do not compose `ToolcraftRoot`, `CanvasShell`, `ControlsPanel`, `LayersPanel`, `TimelinePanel`, or `ToolbarPanel` by hand. If a runtime surface has a performance or behavior issue, fix the shared runtime instead of replacing the surface locally.
|
|
28
|
+
Edit `src/app/app-composition.tsx`, not the signed route. Product composition may provide only `schema`, `canvasContent`, `controlRenderers`, `exportRenderer`, `modelPresentation`, `onPanelAction`, `renderDefaultCanvasMedia`, and optional `rendererPipelineRegistration`; the protected route owns `className` and other host layout. Model products default to `modelPresentation: { mode: "runtime" }`. Custom presentation declares checked consumers and suppresses only their model targets; `renderDefaultCanvasMedia={false}` affects generic image/file preview, not runtime models. Do not compose `ToolcraftRoot`, `CanvasShell`, `ControlsPanel`, `LayersPanel`, `TimelinePanel`, or `ToolbarPanel` by hand. If a runtime surface has a performance or behavior issue, fix the shared runtime instead of replacing the surface locally.
|
|
29
29
|
|
|
30
30
|
Supporting product modules may be organized anywhere under `src`; there is no folder allowlist. The product boundary follows all product production files and rejects host/runtime surface imports, built-in control imports/re-exports, dynamic bypasses, and production dependencies on test/spec modules.
|
|
31
31
|
|
|
@@ -36,7 +36,8 @@ Allowed app extension points:
|
|
|
36
36
|
| Schema controls | Built-in controls, targets, defaults, visibility, panel actions. |
|
|
37
37
|
| `canvasContent` | Product output only. |
|
|
38
38
|
| `controlRenderers` | True custom controls only after the built-in fit check. |
|
|
39
|
-
| `
|
|
39
|
+
| `exportRenderer` | One deterministic scene-coordinate product frame shared by runtime image and video export. |
|
|
40
|
+
| `onPanelAction` | Non-export sticky footer product actions. |
|
|
40
41
|
| `rendererPipelineRegistration` | One compiled executable pipeline shared by render work, actions, evidence, and new-envelope assessment. |
|
|
41
42
|
| Runtime commands/hooks | History, media, canvas, timeline, layers, and controlled app behavior. |
|
|
42
43
|
|
|
@@ -116,7 +117,7 @@ Use one normal sequence: assemble or change the product, gather focused function
|
|
|
116
117
|
|
|
117
118
|
1. First product delivery uses bare `pnpm verify:delivery` for complete product contracts, one production build, full functional acceptance, and no measured performance.
|
|
118
119
|
2. Later `functional-targeted` delivery uses the same bare command for exact ownership-derived functional proof relative to the immediately previous successful delivery.
|
|
119
|
-
3.
|
|
120
|
+
3. Classifier output establishes complaint authority only and never path localization. Only a localized complaint or a post-clarification targeted choice records an exact request quote and canonical affected path IDs in the worklog, then one bare delivery runs one targeted iteration and returns the app for evaluation. Unresolved localization creates neither performance-iteration intent nor canonical path authority regardless of classifier result.
|
|
120
121
|
4. A full audit requires an explicit operator request or accepted offer; only then run `pnpm verify:perf` for one fresh build and the complete maximum-fixture performance matrix.
|
|
121
122
|
|
|
122
123
|
Protected receipts own changed files, the derived plan, executed checks, reports, measurements, and pass/fail evidence. The worklog keeps product intent and decisions.
|
|
@@ -92,8 +92,8 @@ Read this module before changing image upload, file upload, source material impo
|
|
|
92
92
|
- A structurally valid staged draft may preview during analysis without replacing committed state.
|
|
93
93
|
- Analyzing and repairing preview opacity is `40%`; committed preview and export opacity is `100%`.
|
|
94
94
|
- Rotatable model products use `orientationGizmo`. Direct drag on model geometry and the gizmo write the same orientation target against the same presentation lease; a canvas miss remains viewport pan. Preview, undo/reset, and export read that shared pose, canonical document reference, and appearance cache key.
|
|
95
|
-
-
|
|
96
|
-
-
|
|
95
|
+
- Runtime image/video export composites visible committed model layers at the exact scene frame, output size, pixel ratio, and shared orientation before awaiting the product's shared `exportRenderer` frame. Product code does not enumerate model assets, call Three loaders, invoke model compositors, encode canvases, or download artifacts.
|
|
96
|
+
- Every scheduled video frame uses the same runtime model binding and shared pose; it cannot substitute the panel preview or omit model layers.
|
|
97
97
|
|
|
98
98
|
### Persistence And Proof
|
|
99
99
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<!-- toolcraft-performance-lifecycle: first-delivery=functional; later-delivery=functional-targeted; complaint=one-authority-targeted-performance-iteration; full-audit=explicit-only -->
|
|
4
4
|
<!-- toolcraft-performance-iteration: authority=exact-request-evidence+canonical-path-ids; fixture=reachable-development; after-pass=return-app-to-user+stop -->
|
|
5
5
|
<!-- toolcraft-performance-full-authority: automatic=forbidden; recommendation=two-compatible-iterations-or-broad-unlocalizable-problem; command=pnpm verify:perf; authority=explicit-user-request-or-accepted-offer -->
|
|
6
|
+
<!-- toolcraft-performance-routing: localized=agent-targeted; ambiguous=one-user-facing-choice; broad=offer-targeted-or-full; full=explicit-only -->
|
|
6
7
|
|
|
7
8
|
Read this module before changing renderer technique, animation, canvas, media, export, render scale, workload controls, or performance tests.
|
|
8
9
|
|
|
@@ -60,10 +61,18 @@ Include `initial-render` and every reachable interaction that executes or intent
|
|
|
60
61
|
|
|
61
62
|
Browser checks apply compiled values through the real UI, observe every dimension, exercise the real preview or export path, assert the product result, and then check the budget. Export scenarios keep exact `actionValue`, visible `controlLabel`, and `completionEvidence` proof.
|
|
62
63
|
|
|
64
|
+
Selected image/video dimensions, decoded output quality, video duration, and exact 30 FPS packet cadence are functional correctness and never require measured performance authority. Export completion latency and UI responsiveness are measured only for a user-authorized targeted iteration or explicit full audit.
|
|
65
|
+
|
|
63
66
|
## Verification Triggers
|
|
64
67
|
|
|
65
68
|
Keep `src/app/app-verification-impact.json` complete: every product production module is `presentation`, `functional`, or `performance`, every owner names its nearest acceptance ids, and performance owners name their exact renderer pass ids. `performance` means the module can change a named pass's execution, invalidation, workload, resource lifecycle, or measured output. Shared modules name only the acceptance and pass coverage they can actually change; blanket every-module ownership is invalid. The protected delivery runner compares the inventory with the immediately previous successful delivery and requires ownership-derived functional proof for changed implementation. Performance ownership constrains which passes and paths an exact request may authorize; it does not authorize measurements by itself. A durable full-performance baseline, when one exists, remains historical evidence rather than the functional change anchor. Missing modules, stale paths, unknown acceptance or pass ids, and blanket ownership fail before a receipt can be written.
|
|
66
69
|
|
|
70
|
+
Design product module boundaries for this exact later-delivery ownership. Keep frequently changed defaults and domain logic outside the public `app-schema.ts` assembly module when their acceptance coverage is narrower; otherwise a valid edit to that broad owner must select all of its acceptance ids. For raster zoom, prefer viewport transforms, but when exact render-scale backing requires rerasterization, declare one off-main `rasterize` pass with `quality: "retina"` owned by `viewport-zoom`. No other expensive viewport invalidation is accepted.
|
|
71
|
+
|
|
72
|
+
Performance adapters measure one primary user operation per phase; do not include an inverse cleanup action inside the measured operation. Non-animation interaction probes retain at least 20 post-action frames so nearest-rank p95 is statistically distinct from the maximum frame without weakening either threshold.
|
|
73
|
+
|
|
74
|
+
Performance-adapter-only changes remain functional delivery work: run code health and directly affected unit proof, but do not infer measurement. Their path candidates become executable only through exact complaint authority or an explicit full audit.
|
|
75
|
+
|
|
67
76
|
Run targeted functional and browser checks during development. Only exact request authority can create a measured targeted performance iteration; a changed pipeline, workload boundary, adapter, interaction, measured output, owner, pass, path, filename, tier, or subsystem cannot. During an authorized iteration, the targeted Playwright reporter binds passed test names, pass ids, canonical path ids, nonce, and current source hash; product code and prose cannot mint that evidence.
|
|
68
77
|
|
|
69
78
|
Functional performance coverage uses the runtime-owned deferred validation policy: all structural envelope, renderer pipeline, path, fixture, and adapter errors still fail, while unresolved kernel benchmark decisions remain visible as pending assessment requirements and require no kernel receipt. Strict/default validation and every authorized performance run continue to require the decision and protected current-source evidence.
|
|
@@ -74,9 +83,11 @@ The protected conversational lifecycle is automatic:
|
|
|
74
83
|
|
|
75
84
|
- **First product delivery:** bare `pnpm verify:delivery` runs complete product contracts, one production build, and full functional acceptance with no measured performance. It preserves any independent full-performance baseline and cannot claim targeted or full performance evidence.
|
|
76
85
|
- **Later functional-targeted delivery:** the same bare command runs exact ownership-derived functional checks for the changed implementation. It preserves any existing baseline and cannot silently invoke measured performance.
|
|
77
|
-
- **
|
|
86
|
+
- **Localized or clarified targeted work:** only a localized complaint or a post-clarification targeted choice records domain authority in the latest Decision Trail—an exact request quote and canonical affected path IDs—then one bare `pnpm verify:delivery` runs one targeted iteration against the reachable development fixture. Classifier output establishes complaint authority only and never path localization. Any unresolved localization creates neither performance-iteration intent nor canonical path authority, whether classification returned high-confidence `performance-iteration` or `needs-agent-judgment`. The same authority cannot produce a second successful iteration. Deliver the verified app, then stop and wait for user evaluation. Each later localized request may create one new bounded iteration from the immediately previous successful delivery.
|
|
87
|
+
|
|
88
|
+
Request classification is tri-state. High-confidence performance language returns `performance-iteration`; high-confidence ordinary product work remains ordinary; ambiguous or unrecognized language becomes `needs-agent-judgment`, and the AI decides from the complete request. Classifier output establishes complaint authority only and never path localization. A localized complaint lets the agent select affected canonical paths and run one targeted iteration without asking the user. For an ambiguous complaint, ask one user-facing question naming visible operations and offering targeted diagnosis or a complete performance review; never ask the user for internal path IDs, and create neither performance-iteration intent nor canonical path authority before the answer. A broad or honestly unlocalizable problem may lead to that single targeted/full choice with a recommendation for complete performance review, but the user still chooses. An explicit complete-performance-review request runs `pnpm verify:perf` directly. Local negation and product commands are interpreted in their own clause rather than through a global phrase list. Before a performance iteration, the worklog must contain a nontrivial exact raw substring of Request as evidence. Whitespace and Unicode code units must match exactly; invented, whitespace-collapsed, NFKC-equivalent, or otherwise mismatched text is rejected. Complaint wording, repetition, filename, diagnostic classification, and touched subsystem never launch the complete matrix automatically.
|
|
78
89
|
|
|
79
|
-
|
|
90
|
+
Store agent-produced browser diagnostics under `.toolcraft/browser-artifacts/`, or use external tool-owned storage when the browser integration owns the artifact. Diagnostics never become product source or performance authority.
|
|
80
91
|
|
|
81
92
|
Every protected targeted performance report stores the independently validated `cold`, `warm`, and `sustained` numeric observations for each selected canonical path. When the immediately previous successful delivery contains compatible targeted measurements, the next complaint records metric deltas against that report; otherwise it records an explicit non-comparable result. Deltas are diagnostic evidence, not a noisy strict-improvement gate: the current iteration must pass its absolute profile budgets, then return to the user without launching another optimization pass.
|
|
82
93
|
|
|
@@ -92,7 +103,7 @@ Completion wording must name the evidence level. Functional delivery reports fun
|
|
|
92
103
|
|
|
93
104
|
Render Scale preserves selected backing resolution and visible quality. A raster product with `canvas.renderScale` declares typed `renderScaleCoverage: { kind: "selected-backing-pixels", states }` on one browser runtime row targeting `canvas.renderScale`. Exact sorted states are `["interaction", "steady"]`, plus `"playback"` when timeline is enabled.
|
|
94
105
|
|
|
95
|
-
The product browser scenario supplies real state transitions to `expectToolcraftCanvasRenderScaleEvidence`. The protected helper keeps CSS size stable, checks actual canvas backing pixels against `css size × devicePixelRatio × selected scale` in every state, and only then emits `canvas-render-scale-backing` for each `<acceptance-id>#<state>`. A clamp or downsample is a functional failure without measured performance.
|
|
106
|
+
The product browser scenario supplies real state transitions to `expectToolcraftCanvasRenderScaleEvidence`. The protected helper keeps CSS size stable, checks actual canvas backing pixels against `css size × devicePixelRatio × selected scale` in every state, and only then emits `canvas-render-scale-backing` for each `<acceptance-id>#<state>`. A clamp or downsample is a functional failure without measured performance. Every measured path in a render-scale-enabled raster product proves actual `CSS size × devicePixelRatio × 2` backing after each measured phase before `performance-render-scale` evidence may be emitted.
|
|
96
107
|
|
|
97
108
|
Do not pass budgets by silently reducing selected quality, backing resolution, product range, source fidelity, export fidelity, or live interaction semantics. Diagnose pass cost, invalidation, cache lifetime, scheduling, and execution location first.
|
|
98
109
|
|
|
@@ -21,7 +21,8 @@ Use only these app-specific extension points. Shared runtime changes happen upst
|
|
|
21
21
|
- `renderDefaultCanvasMedia={false}` only when a product renderer replaces generic image/file preview; it does not suppress runtime model layers;
|
|
22
22
|
- typed `modelPresentation`, with `{ mode: "runtime" }` as the default standard preview/export owner or `{ mode: "custom", consumers }` for declared model targets with checked consumers;
|
|
23
23
|
- `controlRenderers` only for true custom controls that pass the built-in fit check;
|
|
24
|
-
- `
|
|
24
|
+
- one `exportRenderer` that draws a deterministic product frame for runtime-owned image/video export;
|
|
25
|
+
- `onPanelAction` for non-export sticky product actions;
|
|
25
26
|
- optional `rendererPipelineRegistration` for one compiled executable custom-renderer pipeline shared by product work, runtime evidence, and performance assessment;
|
|
26
27
|
- runtime commands and hooks.
|
|
27
28
|
|
|
@@ -30,6 +31,7 @@ Use only these app-specific extension points. Shared runtime changes happen upst
|
|
|
30
31
|
- Do not hand-compose `ToolcraftRoot`, `CanvasShell`, `ControlsPanel`, `LayersPanel`, `TimelinePanel`, `ToolbarPanel`, or panel containers in product routes.
|
|
31
32
|
- Do not render built-in control components such as `SliderControl`, `SelectControl`, `ColorControl`, `GradientControl`, `FontPickerControl`, `FileDropControl`, or `PanelActionsControl` directly in app code.
|
|
32
33
|
- Do not recreate controls, panels, toolbar, timeline, layers, canvas shell, drag handles, section headers, section reset, history, or runtime surfaces by hand.
|
|
34
|
+
- Do not create product-owned export canvases, encoders, object-URL downloads, or direct Mediabunny integrations; runtime owns typed image/video actions end to end.
|
|
33
35
|
- If a shared behavior is wrong, fix the shared runtime/template source and regenerate or sync the copied Toolcraft source instead of patching one exported app.
|
|
34
36
|
|
|
35
37
|
## Canvas Boundary
|
|
@@ -33,20 +33,22 @@ Read this module before changing Setup, canvas sizing, background, image export,
|
|
|
33
33
|
- Infinity canvas suppresses the bounded product-rendered preview background so the dormant finite output does not appear as a second canvas. While Background is on, `CanvasShell` fills the complete infinite viewport with the selected `Background color`; product code must not draw a synthetic workspace rectangle.
|
|
34
34
|
- The last finite `canvas.size` remains dormant and immutable while Infinity canvas is on. Turning it off restores that exact size and centers the finite artboard; reset, undo/redo, persistence, and settings transfer preserve the same canonical `canvas.mode` behavior. Fixed proof compares exact artboard pixels and width/height control values before Infinity, after restoration, and after redo.
|
|
35
35
|
- Runtime image and model assets keep explicit center-anchored world frames. Zoom, pan, radar, and model orientation change presentation, not scene geometry or export bounds.
|
|
36
|
-
- Product `canvasContent` and custom renderer output declare one direct `ToolcraftAppComposition.sceneBoundsProvider`. It returns product world-space rectangles
|
|
36
|
+
- Product `canvasContent` and custom renderer output declare one direct `ToolcraftAppComposition.sceneBoundsProvider`. It returns product world-space rectangles for the supplied exact frame state; do not use a registry, DOM measurement, or app-authored time-range envelope.
|
|
37
37
|
- Infinite PNG export crops to the outward-rounded union of visible product, image, and model frames. Hidden or unavailable layers, runtime media suppressed by the composition, and editor-only handles or gizmos are excluded.
|
|
38
38
|
- Prove unavailable-image exclusion with `createToolcraftUnavailableImageResourceFixture` and `expectToolcraftInfinityCanvasUnavailableImageExportEvidence`; product tests never mutate storage/state or call the reserved bridge, and evidence publishes only after deterministic cleanup restores the ready resource.
|
|
39
|
-
- Infinite video export
|
|
39
|
+
- Infinite video export asks the provider for every state in the runtime-owned frame schedule, unions those bounds once, and uses the result for every encoded frame, preventing frame-to-frame output size changes.
|
|
40
40
|
- Finite-mode export remains the full finite canvas and does not call the product bounds provider.
|
|
41
41
|
- Empty scenes, missing/invalid product bounds, and artifacts above `8192px` per edge or `67,108,864` pixels fail before canvas allocation with visible typed feedback: `empty-scene`, `scene-bounds-unavailable`, or `scene-export-too-large`.
|
|
42
42
|
|
|
43
43
|
## Resolution Scale
|
|
44
44
|
|
|
45
|
-
- Non-vector raster, Canvas 2D, WebGL, and WebGPU previews
|
|
45
|
+
- Non-vector raster, Canvas 2D, WebGL, and WebGPU previews author `canvas.renderScale` as `true` or `{ step }`. For this control, product code may customize only the slider step; it cannot author `enabled`, `min`, `defaultValue`, or `max`.
|
|
46
|
+
- Runtime resolves the enabled slider to canonical `min: 1`, `defaultValue: 2`, and `max: 2`; the default step is `0.25`.
|
|
47
|
+
- A custom step must be finite, between `0.01` and `1`, and evenly partition the canonical `1..2` range so the `2` maximum remains reachable. Invalid or non-partitioning steps fail schema resolution instead of being clamped.
|
|
46
48
|
- Runtime then appends `Resolution scale` after canvas sizing.
|
|
47
49
|
- `Resolution scale` changes backing pixels from `1` to `2` without changing visible CSS size or product output dimensions.
|
|
48
50
|
- The product acceptance matrix adds exactly one browser runtime row targeting `canvas.renderScale` with `renderScaleCoverage: { kind: "selected-backing-pixels", states: ["interaction", "steady"] }`; insert `"playback"` in sorted order when timeline is enabled.
|
|
49
|
-
- The product browser scenario uses `expectToolcraftCanvasRenderScaleEvidence` for every declared state. Only after CSS size remains stable and actual backing dimensions
|
|
51
|
+
- The product browser scenario uses `expectToolcraftCanvasRenderScaleEvidence` for every declared state. Only after CSS size remains stable and actual backing dimensions equal `css size × devicePixelRatio × selected scale` within the one-physical-pixel tolerance does the protected reporter emit `canvas-render-scale-backing`.
|
|
50
52
|
- Any quality clamp or lower-resolution stretch is a functional failure without measured performance.
|
|
51
53
|
- DOM/SVG/vector-native previews should not use render scale.
|
|
52
54
|
- Performance fixes must preserve the user's selected render scale. Do not pass budgets by silently downsampling, stretching a lower-resolution backing canvas, blurring output, or clamping render scale below the chosen value.
|
|
@@ -70,8 +72,8 @@ Read this module before changing Setup, canvas sizing, background, image export,
|
|
|
70
72
|
- Use a schema `color` target such as `appearance.background` or `scene.background`.
|
|
71
73
|
- Do not hardcode a configurable background in CSS, Canvas `fillStyle`, or WebGL clear color.
|
|
72
74
|
- Live preview calls `shouldIncludeToolcraftPreviewBackground(state)` and hides only the bounded product-rendered background when Background is off or Infinity canvas is on. In Infinity mode, the runtime viewport—not the product renderer—uses the selected Background color.
|
|
73
|
-
-
|
|
74
|
-
-
|
|
75
|
+
- Runtime image export reads Background directly: PNG can be transparent, while JPG remains opaque.
|
|
76
|
+
- Runtime video export keeps the selected background even when Background is off.
|
|
75
77
|
|
|
76
78
|
## Image Export
|
|
77
79
|
|
|
@@ -81,7 +83,8 @@ Read this module before changing Setup, canvas sizing, background, image export,
|
|
|
81
83
|
- `export.image.resolution`, default `4k`, with baseline `2K`, `4K`, and `8K` options.
|
|
82
84
|
- Still-output apps place `Image Export` directly above sticky footer actions.
|
|
83
85
|
- Apps with both image and video export place `Image Export` immediately before `Video Export`.
|
|
84
|
-
-
|
|
86
|
+
- Typed `export-image` actions are handled by the runtime. It resolves the current scene frame, selected format and resolution, allocates the exact backing, composites background plus visible runtime media/models, awaits `ToolcraftAppComposition.exportRenderer`, encodes the selected artifact, downloads it, and reports typed progress/failures.
|
|
87
|
+
- Product code supplies only the shared deterministic `exportRenderer.renderFrame` callback in scene coordinates. It must not allocate an export canvas, call `toBlob`/`toDataURL`, create object URLs, or download the artifact.
|
|
85
88
|
- The selected `export.image.resolution` must produce real 2048/4096/8192px long-edge PNG output for 2K/4K/8K. Retina sizing is only the fallback for current/omitted resolution.
|
|
86
89
|
|
|
87
90
|
## Video Export
|
|
@@ -93,11 +96,12 @@ Read this module before changing Setup, canvas sizing, background, image export,
|
|
|
93
96
|
- `export.video.format`, default `mp4`, with baseline `MP4` and `WebM` options;
|
|
94
97
|
- `export.video.resolution`, default `current`, with baseline `Current` and `4K` options.
|
|
95
98
|
- Stack the pair only when labels or selected values would clip, and record that fit reason in the worklog.
|
|
96
|
-
-
|
|
99
|
+
- Runtime uses the pinned Mediabunny timestamped encoder to select an actually supported container and codec. It reports the real MIME/extension or a typed visible failure.
|
|
97
100
|
- `MOV` and `ProRes` are not baseline browser outputs; use them only with a custom encoder/transcoder plus acceptance and performance coverage.
|
|
98
101
|
- Use `getToolcraftVideoExportSize` for video dimensions. `current` uses current canvas/output size with even encoder-safe rounding; `4k` fits inside 3840x2160, preserves aspect ratio, and returns even dimensions.
|
|
99
|
-
-
|
|
100
|
-
-
|
|
102
|
+
- Runtime renders the same shared product frame callback at a fixed 30 FPS offline schedule, evaluates each immutable frame state at its timeline timestamp, and writes explicit packet timestamps/durations. Renderer wall-clock cost changes export latency only, never media cadence or duration.
|
|
103
|
+
- Product code must not instantiate `MediaRecorder` or `VideoEncoder`, call `canvas.captureStream()`, import `mediabunny`, or provide a wall-clock fallback.
|
|
104
|
+
- Protected browser acceptance decodes representative video frames, enumerates actual encoded packet timings, and proves dimensions, duration, cadence, background, and changing product pixels before publishing evidence.
|
|
101
105
|
|
|
102
106
|
## Sticky Product Actions
|
|
103
107
|
|
|
@@ -106,5 +110,5 @@ Read this module before changing Setup, canvas sizing, background, image export,
|
|
|
106
110
|
- Products whose requested delivery includes animation also expose `Export Video`.
|
|
107
111
|
- Clipboard copy is optional and never replaces export.
|
|
108
112
|
- Export PNG and Export Video use `icon: "upload-simple"` to match the runtime `Export Settings` action.
|
|
109
|
-
-
|
|
110
|
-
-
|
|
113
|
+
- Runtime export actions own their real Promise and report render/encode/download progress through the sticky footer indicator.
|
|
114
|
+
- Async non-export download/copy/generate/apply handlers return the real Promise from `onPanelAction` and use `reportProgress(0..1)` when determinate progress is available.
|