@pixel-point/toolcraft 0.0.8 → 0.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +42 -9
  2. package/package.json +1 -1
  3. package/src/generate.mjs +42 -5
  4. package/src/generate.test.mjs +40 -0
  5. package/src/package-json.mjs +15 -0
  6. package/src/package-json.test.mjs +14 -1
  7. package/templates/runtime/contracts/component-contracts.test.ts +251 -47
  8. package/templates/runtime/contracts/component-contracts.ts +130 -57
  9. package/templates/runtime/contracts/decision-contracts.test.ts +38 -1
  10. package/templates/runtime/contracts/decision-contracts.ts +22 -9
  11. package/templates/runtime/export/export.test.ts +63 -0
  12. package/templates/runtime/export/export.ts +55 -0
  13. package/templates/runtime/index.ts +1 -0
  14. package/templates/runtime/react/canvas-shell.test.tsx +58 -4
  15. package/templates/runtime/react/canvas-shell.tsx +31 -9
  16. package/templates/runtime/react/controls-panel.test.tsx +916 -108
  17. package/templates/runtime/react/controls-panel.tsx +136 -30
  18. package/templates/runtime/react/runtime-public-api.test.tsx +1 -1
  19. package/templates/runtime/react/settings-transfer.test.ts +4 -0
  20. package/templates/runtime/react/settings-transfer.ts +6 -1
  21. package/templates/runtime/react/timeline-panel.test.tsx +14 -0
  22. package/templates/runtime/react/timeline-panel.tsx +44 -7
  23. package/templates/runtime/react/toolcraft-app.integration.test.tsx +9 -1
  24. package/templates/runtime/react/toolcraft-app.test.tsx +112 -3
  25. package/templates/runtime/react/toolcraft-app.tsx +56 -37
  26. package/templates/runtime/schema/define-toolcraft.test.ts +266 -170
  27. package/templates/runtime/schema/define-toolcraft.ts +140 -246
  28. package/templates/runtime/schema/runtime-targets.ts +21 -0
  29. package/templates/runtime/schema/types.ts +44 -0
  30. package/templates/runtime/state/create-template-state.test.ts +156 -0
  31. package/templates/runtime/state/create-template-state.ts +38 -8
  32. package/templates/runtime/state/media-defaults.ts +105 -0
  33. package/templates/runtime/state/persistence.test.ts +58 -0
  34. package/templates/runtime/state/persistence.ts +105 -1
  35. package/templates/runtime/state/reducer.test.ts +280 -4
  36. package/templates/runtime/state/reducer.ts +195 -9
  37. package/templates/runtime/state/timeline-loop.test.ts +71 -0
  38. package/templates/runtime/state/timeline-loop.ts +35 -0
  39. package/templates/runtime/state/types.ts +27 -0
  40. package/templates/runtime/testing/performance.test.ts +810 -21
  41. package/templates/runtime/testing/performance.ts +823 -53
  42. package/templates/starter/AGENTS.md +24 -18
  43. package/templates/starter/docs/toolcraft/README.md +8 -4
  44. package/templates/starter/docs/toolcraft/acceptance-testing.md +43 -10
  45. package/templates/starter/docs/toolcraft/agent-worklog.md +1 -0
  46. package/templates/starter/docs/toolcraft/assembly-workflow.md +55 -20
  47. package/templates/starter/docs/toolcraft/component-rules.md +75 -42
  48. package/templates/starter/docs/toolcraft/decision-contract.md +2 -0
  49. package/templates/starter/docs/toolcraft/performance.md +37 -11
  50. package/templates/starter/docs/toolcraft/schema-reference.md +171 -41
  51. package/templates/starter/docs/toolcraft/workflow.md +5 -2
  52. package/templates/starter/e2e/app-browser-acceptance.spec.ts +3 -3
  53. package/templates/starter/e2e/app-performance.spec.ts +55 -2
  54. package/templates/starter/e2e/performance-helpers.ts +45 -0
  55. package/templates/starter/gitignore +1 -0
  56. package/templates/starter/index.html +1 -0
  57. package/templates/starter/package.json +3 -0
  58. package/templates/starter/playwright.config.ts +1 -1
  59. package/templates/starter/scripts/check-toolcraft-docs.mjs +1 -0
  60. package/templates/starter/scripts/run-vite-on-free-port.mjs +114 -13
  61. package/templates/starter/scripts/toolcraft-port.mjs +280 -0
  62. package/templates/starter/scripts/toolcraft-port.test.mjs +207 -1
  63. package/templates/starter/src/app/starter-acceptance.test.ts +3412 -479
  64. package/templates/starter/src/app/starter-acceptance.ts +1453 -97
  65. package/templates/starter/src/app/starter-performance.test.ts +111 -7
  66. package/templates/starter/src/app/starter-performance.ts +5 -0
  67. package/templates/starter/src/app/starter-schema.test.ts +32 -7
  68. package/templates/starter/src/app/starter-schema.ts +6 -2
  69. package/templates/starter/vite.config.ts +58 -2
  70. package/templates/ui/components/control-layout/index.tsx +8 -3
  71. package/templates/ui/components/controls/actions/actions-control.tsx +56 -5
  72. package/templates/ui/components/controls/code-textarea/code-textarea-control.tsx +7 -3
  73. package/templates/ui/components/controls/color/index.ts +4 -1
  74. package/templates/ui/components/controls/color/palette-control.tsx +34 -4
  75. package/templates/ui/components/controls/color/style-guide-color-picker-logic.ts +7 -2
  76. package/templates/ui/components/controls/color/style-guide-color-picker.tsx +2 -2
  77. package/templates/ui/components/controls/file-drop/file-drop-control.tsx +186 -14
  78. package/templates/ui/components/controls/file-drop/index.ts +6 -1
  79. package/templates/ui/components/controls/index.ts +4 -0
  80. package/templates/ui/components/controls/range-input/range-input-control.tsx +12 -4
  81. package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -1
  82. package/templates/ui/components/controls/select/select-control.tsx +8 -25
  83. package/templates/ui/components/controls/slider/slider-value.ts +0 -1
  84. package/templates/ui/components/controls/text-input/text-input-control.tsx +4 -1
  85. package/templates/ui/components/controls/vector/index.ts +1 -0
  86. package/templates/ui/components/controls/vector/vector-control.tsx +109 -12
  87. package/templates/ui/components/panel/panel-actions.tsx +1 -1
  88. package/templates/ui/components/panel/panel-section.tsx +29 -5
@@ -14,22 +14,23 @@ Then follow `workflow.md` to choose the required contract docs and verification
14
14
 
15
15
  1. Build through `defineToolcraft` and `ToolcraftApp`.
16
16
  2. Keep app state in Toolcraft runtime schema and commands.
17
- 3. Keep product output in `canvasContent`; never render app UI there.
17
+ 3. Keep product output in `canvasContent`; never render app UI there. If upload/import is part of the source-material flow, do not invent canvas placeholder artwork, CTA copy, helper text, fake sample output, or preset source designs before real content exists.
18
18
  4. Use built-in Toolcraft controls before custom controls.
19
19
  5. Do not hand-compose runtime surfaces or render built-in control components directly in app code; use `ToolcraftApp`, schema controls, `canvasContent`, `controlRenderers`, `onPanelAction`, and runtime commands.
20
- 6. Before writing controls, make a Control Section Inventory that groups controls by product entity or workflow stage, not by UI component type.
20
+ 6. Before writing controls, make and export `starterControlSectionInventory`: each product controls section declares its title, product entity or workflow stage, targets, and grouping reason. Group by product meaning, not UI component type.
21
21
  7. Keep control `label` short but semantically sufficient with the nearest visible section/group context, and put product-specific behavior help in schema `description`; runtime renders the label help tooltip only when that description adds meaning beyond the label.
22
- 8. Enable layers and timeline only when product behavior requires them, then test the real UI.
22
+ 8. Enable layers and timeline only when product behavior requires them, then test the real UI. Product animation loops are seamless forward-only by default: first and last frames stitch, direction does not reverse, and mirror/yoyo/ping-pong behavior requires explicit user intent.
23
23
  9. Animated preview renderers suspend or coalesce non-essential animation work during canvas drag, pan, pinch, zoom, and radar/center interactions, then resume without changing user playback state.
24
24
  10. If a Figma URL is provided, inspect the Figma file through MCP and rebuild from its structure; never implement from a screenshot or by eye.
25
- 11. Choose an explicit persistence policy; use schema `persistence` for user-edited app settings that should survive reload, and test real reload restoration when localStorage is enabled.
26
- 12. Use schema `settingsTransfer: "auto"` for complex apps that need import/export of control settings; never implement settings import/export through `panelActions` or route-local file inputs. After adding, removing, or reorganizing controls, sections, timeline, or layers, recalculate settings-transfer eligibility. The runtime threshold is 12 product controls, 5 product sections, or weighted score 18. Visible `Aspect ratio`, `Canvas width`, and `Canvas height` controls are owned by `editable-output` canvas sizing, not by settings transfer. Runtime aspect presets apply canonical canvas sizes, with `16:9` equal to `1920x1080`; manual Canvas width/height edits keep the typed dimension, keep the other dimension unchanged, switch Aspect ratio to Custom, and show the reduced current ratio in custom ratio inputs; when no explicit product size is provided, the runtime default canvas size is also `1920x1080`. Non-vector raster, Canvas 2D, WebGL, and WebGPU previews set `canvas.renderScale: true`; the first technical runtime section then appends `Resolution scale` after canvas sizing so backing pixels can increase up to 2x without changing CSS/output size. Performance fixes must preserve the selected render scale and keep canvas preview responsive to sliders/high-frequency controls at that scale; diagnose the bottleneck before reducing quality. Do not pass budgets by silently downsampling, stretching a lower-resolution backing canvas, blurring output, or clamping `canvas.renderScale` below the user's chosen value. When settings transfer and editable-output canvas sizing are both enabled, the first technical `Setup` runtime section contains `Export Settings`, `Import Settings`, `Aspect ratio`, `Canvas width`, `Canvas height`, and, for raster outputs, `Resolution scale` in that order and renders without a visible section heading.
27
- 13. Product apps expose a required `Background` section directly before export settings. It contains a Switch labeled `Include` and a background color control with `label: false` in one equal-width inline row; PNG export wires those runtime values into the standard export helper, live preview uses `shouldIncludeToolcraftPreviewBackground(state)` so Include can hide the product background, and video export keeps the background. Every app with `Export PNG` exposes `Image Export` with `export.image.format` and `export.image.resolution` as two `select` controls in one compact two-column inline row, and passes the selected resolution to `createToolcraftPngExportCanvas({ resolution })` so 2K/4K/8K change actual PNG dimensions. Animated apps with both PNG and video export place `Image Export` immediately before `Video Export`.
28
- 14. Keep `docs/toolcraft/agent-worklog.md` current with a decision trail, product decisions, evidence, verification, and risks.
29
- 15. Prove every visible entity through acceptance, browser, and performance coverage.
30
- 16. Workload performance scenarios must declare `stressFixture` for the tested control value; browser perf tests must use `getToolcraftPerformanceStressValue(appPerformance, scenarioId)` so heavy-case tests cannot use toy values. When the tested control is not itself the whole heavy source, declare `workloadFixture` and apply it first with `getToolcraftPerformanceWorkloadValue` or `applyToolcraftPerformanceWorkloadFixture`; this is the app baseline such as large media, long text, many items, or high render scale, and it must be paired with the measured `stressFixture`. Media import and image-processing workloads use `kind: "media"` fixtures at least `1920x1080`-equivalent, and heavy pixel/media Canvas 2D must evaluate WebGL/WebGPU with measured evidence before staying on CPU.
31
- 17. Custom renderer apps declare a Render Pipeline Inventory in typed `rendererPipeline`: render passes, cache keys, execution location, preview/export quality, and interaction invalidation.
32
- 18. Classify every implementation pass with a verification tier before editing. Use targeted checks for incremental edits and the full final gate only for final delivery, exports, or architecture/runtime/template changes.
25
+ 11. If a video, GIF, screen recording, contact sheet, or extracted-frame sequence is provided as a reference, write 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.
26
+ 12. Choose an explicit persistence policy; use schema `persistence` for user-edited app settings that should survive reload, and test real reload restoration when localStorage is enabled.
27
+ 13. Generated apps keep a controls panel so runtime `Setup` is visible from the first run; product sections are added after it. Runtime `Setup` is the first visible headerless controls block, is not collapsible, and always contains `Export Settings` and `Import Settings`; never implement settings import/export through `panelActions` or route-local file inputs, and never gate this block by app complexity. Visible `Aspect ratio`, `Canvas width`, and `Canvas height` controls are owned by `editable-output` canvas sizing and merge into the same Setup block after settings transfer. 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. Runtime aspect presets apply canonical canvas sizes, with `16:9` equal to `1920x1080`; manual Canvas width/height edits keep the typed dimension, keep the other dimension unchanged, switch Aspect ratio to Custom, and show the reduced current ratio in custom ratio inputs; when no explicit product size is provided, the runtime default canvas size is also `1920x1080`. Product-output, exportable, shader, procedural, and reference-clone apps use `editable-output`; uploaded background/source images inside product canvases also use `editable-output`, keep the current canvas size, and render as cover/crop inside the current canvas bounds. Fixed/reference/base dimensions are initial `canvas.size` values, not reasons to hide `Aspect ratio`, `Canvas width`, or `Canvas height`. Non-vector raster, Canvas 2D, WebGL, and WebGPU previews set `canvas.renderScale: true`; Setup then appends `Resolution scale` after canvas sizing so backing pixels can increase up to scale 2 without changing CSS/output size. Performance fixes must preserve the selected render scale and keep canvas preview responsive to sliders/high-frequency controls at that scale; diagnose the bottleneck before reducing quality. Do not pass budgets by silently downsampling, stretching a lower-resolution backing canvas, blurring output, or clamping `canvas.renderScale` below the user's chosen value. When `panels.timeline` is enabled, runtime appends a `Timeline` switch as the last Setup control; off shows compact Play-only transport, on shows the extended timeline with scrubber, duration, loop, and keyframe UI, and the switch never changes product values, playback, keyframes, export, or Reset controls. When `panels.timeline` is omitted, the Timeline switch must not appear.
28
+ 14. Product apps expose a required `Background` section directly before export settings. It contains a Switch labeled `Include` and a background color control with `label: false` in one equal-width inline row; PNG export wires those runtime values into the standard export helper, live preview uses `shouldIncludeToolcraftPreviewBackground(state)` so Include can hide the product background, and video export keeps the background. Every app with `Export PNG` exposes `Image Export` with `export.image.format` and `export.image.resolution` as two `select` controls in one compact two-column inline row, and passes the selected resolution to `createToolcraftPngExportCanvas({ resolution })` so 2K/4K/8K change actual PNG dimensions. Animated apps with video export enable the top Toolcraft timeline and place `Image Export` immediately before `Video Export`.
29
+ 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.
30
+ 16. Prove every visible entity through acceptance, browser, and performance coverage.
31
+ 17. Workload performance scenarios must declare `stressFixture` for the tested control value; browser perf tests must use `getToolcraftPerformanceStressValue(appPerformance, scenarioId)` so heavy-case tests cannot use toy values. When the tested control is not itself the whole heavy source, declare `workloadFixture` and apply it first with `getToolcraftPerformanceWorkloadValue` or `applyToolcraftPerformanceWorkloadFixture`; this is the app baseline such as large media, long text, many items, or high render scale, and it must be paired with the measured `stressFixture`. Numeric maximums, density, item counts, canvas/media size, and combined heavy states declare `loadProfile` with `hardLimit`, `smoothTarget`, and `smoothTargetRatio`; try the hard limit first, and lower the guaranteed smooth target only in 10 percent steps with failed-measurement and optimization evidence. Ranges above `smoothTarget` are experimental, not silently guaranteed. Media import and image-processing workloads use `kind: "media"` fixtures at least `1920x1080`-equivalent, and heavy pixel/media Canvas 2D must evaluate WebGL/WebGPU with measured evidence before staying on CPU.
32
+ 18. Custom renderer apps declare a Render Pipeline Inventory in typed `rendererPipeline`: render passes, cache keys, execution location, preview/export quality, and interaction invalidation.
33
+ 19. Classify every implementation pass with a verification tier before editing. Use targeted checks for incremental edits and the full final gate only for final delivery, exports, or architecture/runtime/template changes.
33
34
 
34
35
  ## Starter Baseline
35
36
 
@@ -84,6 +85,7 @@ These ids mirror `TOOLCRAFT_DECISION_CONTRACT` in `@/toolcraft/runtime`. Keep th
84
85
  - `output-export-required`
85
86
  - `controls-layout-heuristics`
86
87
  - `renderer-technique-inventory`
88
+ - `video-reference-analysis`
87
89
  - `reference-clone-source-of-truth`
88
90
  - `acceptance-product-observable`
89
91
  - `performance-coverage-levels`
@@ -99,7 +101,7 @@ These ids mirror `TOOLCRAFT_DECISION_CONTRACT` in `@/toolcraft/runtime`. Keep th
99
101
  - Use `renderDefaultCanvasMedia={false}` when a custom renderer replaces the default media preview.
100
102
  - Use `ToolcraftApp onPanelAction` for sticky footer product actions such as Generate, Apply, Export, Copy, or Download.
101
103
  - Keep final app behavior in the schema and runtime command bus, not in isolated local control state.
102
- - 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.
104
+ - 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.
103
105
  - 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.
104
106
  - Use schema `defaultValue` for every resettable control.
105
107
  - Route editor-owned actions through runtime commands such as `controls.reset`, `media.import`, `media.delete`, `canvas.center`, `history.undo`, and `history.redo`.
@@ -112,7 +114,7 @@ AI must work on this app through the required workflow skills when the environme
112
114
  - Before editing code from an approved spec, use `writing-plans` to produce a deterministic implementation plan focused on app files, tests, build, and browser verification.
113
115
  - Before fixing any broken control, failed test, build failure, visual mismatch, export issue, or runtime regression, use `systematic-debugging` to find the root cause first.
114
116
  - When the prompt includes a Figma URL, use Figma MCP/design context before implementation. Read the actual node, layer, component, variable, and asset structure; screenshots are only for final visual QA, not the source of truth.
115
- - After implementation, use the `browser` workflow or equivalent local browser verification to test the running app, not only typecheck/build output. The default browser gate is `pnpm test:browser`; `pnpm test:browser:perf` is reserved for full performance checkpoints.
117
+ - After implementation, use the `browser` workflow or equivalent local browser verification to test the running app, not only typecheck/build output. The default browser gate is `pnpm test:browser`; it excludes `browser perf:` budget scenarios and leaves the performance audit disabled unless the perf checkpoint runner sets `TOOLCRAFT_PERF_CHECK=1`. `pnpm test:browser:perf` is reserved for full performance checkpoints.
116
118
  - Run `pnpm ai:check` before app generation or major changes.
117
119
  - If a required skill is missing and the environment supports skill installation, install it before implementation and restart or refresh the session if the skill list does not update.
118
120
  - If skill installation is not available, stop before implementation and tell the user exactly which required skills are missing.
@@ -141,16 +143,18 @@ Choose the tier by blast radius, not by line count. If uncertain, move one tier
141
143
  | Tier 1 — local control presentation | One control or panel visual state changes: spacing, hover, focus, disabled, marker visibility, label fit, or component variant display. Runtime state shape and product renderer are unchanged. | Targeted unit/component test plus one focused browser check for the affected control or panel. |
142
144
  | Tier 2 — schema/product behavior | Controls, sections, defaults, persistence, panel actions, export actions, acceptance rows, or product behavior mapping changes. | `pnpm verify:quick` plus relevant browser acceptance. Run perf only when the changed control affects renderer workload or responsiveness. |
143
145
  | Tier 3 — renderer/canvas/runtime feature | Custom renderer, animation loop, canvas sizing, upload/media, timeline, layers, toolbar, export bytes, WebGL/Canvas/SVG output, zoom, radar, history, heavy control behavior changes, or a post-generation iteration that touches renderer workload or viewport stability. | `pnpm verify:quick`, targeted browser acceptance, and targeted performance scenarios only for touched workload/viewport/export paths. |
144
- | Tier 4 — final delivery/template architecture | Fresh generated app completion, folder export, commit-ready delivery, dependency changes, runtime/template/contract/CLI changes, broad refactors, or major post-generation iterations that rewrite renderer, canvas, animation, timeline/keyframes, layers, media, export, or control mapping. | Fresh folders run `pnpm install` once, then `pnpm verify:final`; add `pnpm verify:perf` only for the first working app version or explicit performance complaints, then start `pnpm dev` to provide the local URL. |
146
+ | Tier 4 — final delivery/template architecture | Fresh generated app completion, folder export, commit-ready delivery, dependency changes, runtime/template/contract/CLI changes, broad refactors, or major post-generation iterations that rewrite renderer, canvas, animation, timeline/keyframes, layers, media, export, or control mapping. | Fresh folders run `pnpm install` once, then `pnpm verify:final`; for the first working product version also run and pass a browser performance checkpoint with the current AI agent's controlled browser when available, using `pnpm verify:perf` only as the Playwright fallback for CI/non-agent runs or agents without a browser, then start `pnpm dev` to provide the local URL. |
145
147
 
146
148
  Do not rerun `pnpm install` after every edit. Run it after fresh export, dependency changes, lockfile changes, or a missing package error.
147
149
 
148
150
  Do not run the full browser performance suite for Tier 0-2 edits.
149
151
 
150
- Run a full performance checkpoint with `pnpm verify:perf` only when the first working version of an app exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance.
152
+ Run a full performance checkpoint only when the first working version of an app exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance. Prefer the current AI agent's controlled browser. Use `pnpm verify:perf` only when no agent-controlled browser is available or when running CI/non-agent automation.
151
153
 
152
154
  Feature loops after the first working version do not run the full performance suite by default. Renderer, canvas, animation, export, timeline, layers, `canvas.renderScale`, bug fixes, and performance-sensitive controls still need targeted functional/browser checks first, plus targeted performance scenarios only when they directly exercise the touched workload/viewport/export path. Record any skipped full performance run and reason in the verification note or worklog.
153
155
 
156
+ The first working product app version is not complete until `pnpm verify:final` and the required browser performance checkpoint have passed and the worklog records the runner as `agent-browser` or `playwright-fallback`. Do not report final delivery when required checks are failed, incomplete, pending, blocked, or listed as skipped. After the first working version, a skipped full performance run is valid only when the worklog explicitly says the full performance checkpoint is not required for a post-first-working non-performance edit.
157
+
154
158
  ## Required Checks
155
159
 
156
160
  For final delivery, run:
@@ -160,11 +164,13 @@ pnpm verify:final
160
164
  pnpm dev
161
165
  ```
162
166
 
167
+ For the first working product delivery, run the browser performance checkpoint after `pnpm verify:final` and before `pnpm dev`: use the agent-controlled browser when available, otherwise run `pnpm verify:perf` as the Playwright fallback.
168
+
163
169
  Use `pnpm install` before this final gate when the folder is fresh or dependencies changed.
164
170
 
165
- `pnpm test` must include `node scripts/check-toolcraft-docs.mjs`, `node scripts/check-toolcraft-integrity.mjs`, and app tests. `pnpm verify:ui` / `pnpm test:browser` must run against the real app UI and product output. `pnpm verify:perf` / `pnpm test:browser:perf` remains available for the two full-performance triggers and must run the performance browser suite sequentially so budgets are measured without parallel e2e noise.
171
+ `pnpm test` must include `node scripts/check-toolcraft-docs.mjs`, `node scripts/check-toolcraft-integrity.mjs`, and app tests. `pnpm verify:ui` / `pnpm test:browser` must run against the real app UI and product output but must not run `browser perf:` budget scenarios or the performance audit. `pnpm verify:perf` / `pnpm test:browser:perf` remains available as the Playwright fallback for the two full-performance triggers and must run the performance audit plus browser budget suite sequentially so budgets are measured without parallel e2e noise.
166
172
 
167
- Do not stop or kill existing local servers to free a port. `pnpm dev`, `pnpm preview`, and browser verification prefer port `3002`, but automatically move to the next free port when it is busy. Use `TOOLCRAFT_PORT`, `TOOLCRAFT_DEV_PORT`, or `TOOLCRAFT_TEST_PORT` only to change the preferred starting port.
173
+ Do not stop or kill existing local servers to free a port during a first start. `pnpm dev`, `pnpm preview`, and browser verification prefer port `3002`, but automatically move to the next free port only while assigning this app's first saved port. After a saved port exists, normal `pnpm dev` / `pnpm preview` uses that same port; if that port is already serving this app, report that existing URL instead of starting a duplicate. Use `TOOLCRAFT_PORT`, `TOOLCRAFT_DEV_PORT`, or `TOOLCRAFT_TEST_PORT` only to change the preferred starting port before a saved port exists. A dev/preview launch is successful only after the selected port serves this app's Toolcraft server identity endpoint plus the `toolcraft-app-title` marker from `index.html`; never report a URL just because some server is listening there. When deliberately restarting this app server, use `pnpm dev:restart` or `pnpm preview:restart`; restart mode reuses the previously saved app port, stops the listener on that exact port if it is still running, force-stops it if it does not release the port, starts on the same port again, and verifies the identity before saving/reporting the port.
168
174
 
169
175
  ## App Completion Bar
170
176
 
@@ -180,7 +186,7 @@ The app is complete only when:
180
186
  - PNG export uses the required `Background` section with `Include` plus unlabeled background color runtime controls, live preview hides product background when Include is off, and video keeps background;
181
187
  - every PNG export includes `Image Export` format/resolution `select` controls, and passes `export.image.resolution` into `createToolcraftPngExportCanvas`;
182
188
  - animated products with both PNG and video export place `Image Export` immediately before `Video Export`;
183
- - all export paths use retina output dimensions from the standard export helper;
189
+ - export paths use the standard export helpers: PNG uses selected image resolution or retina fallback, while video uses current canvas/output size or the selected 4K target;
184
190
  - layers are absent for single-layer apps and fully working when enabled;
185
191
  - timeline is absent, playback, keyframes, or custom reference timeline according to product behavior;
186
192
  - performance checks cover workload and responsiveness for all relevant controls;
@@ -27,16 +27,20 @@ Every implementation pass must choose a verification tier before editing. Use th
27
27
  | Tier 1 | One control or panel visual state | targeted test + focused browser check |
28
28
  | Tier 2 | Schema, defaults, persistence, actions, product mapping | `pnpm verify:quick` + relevant browser acceptance |
29
29
  | Tier 3 | Renderer, canvas, timeline, layers, upload, export, zoom, heavy controls, or a touched performance-sensitive path | `pnpm verify:quick` + targeted browser checks, plus targeted perf scenarios only for the touched path |
30
- | Tier 4 | Final delivery, fresh export, runtime/template/contract changes, broad renderer/product rewrites | `pnpm verify:final`; add `pnpm verify:perf` only for the first working app version or explicit performance complaints |
30
+ | Tier 4 | Final delivery, fresh export, runtime/template/contract changes, broad renderer/product rewrites | `pnpm verify:final`; for the first working product version also run and pass a browser performance checkpoint with the agent-controlled browser when available, using `pnpm verify:perf` only as fallback |
31
31
 
32
- Run the full `pnpm verify:perf` suite only when the first working app version exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance.
32
+ Run the full performance checkpoint only when the first working app version exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance. Prefer the current AI agent's controlled browser. Use `pnpm verify:perf` only when no agent browser is available or in CI/non-agent automation.
33
+
34
+ Performance fixtures use `loadProfile` for reasoned workload ceilings: test the product hard limit first, and only lower the guaranteed `smoothTarget` in 10 percent steps with failed-measurement and optimization evidence. Ranges above the smooth target must be treated as experimental, not silently guaranteed.
35
+
36
+ The first working product app version is not complete until `pnpm verify:final` and the required browser performance checkpoint have passed and the worklog records the runner as `agent-browser` or `playwright-fallback`. Do not report final delivery when required checks are failed, incomplete, pending, blocked, or listed as skipped. After the first working version, a skipped full performance run is valid only when the worklog explicitly says the full performance checkpoint is not required for a post-first-working non-performance edit.
33
37
 
34
38
  Fresh folders or dependency changes need `pnpm install` before verification. Final delivery still starts the local app after the gate:
35
39
 
36
40
  ```bash
37
41
  pnpm verify:final
38
- pnpm verify:perf # first working version or explicit performance complaint only
42
+ pnpm verify:perf # Playwright fallback when no agent browser is available or in CI/non-agent automation
39
43
  pnpm dev
40
44
  ```
41
45
 
42
- Do not kill existing local servers to free `3002`. Dev, preview, and browser verification prefer `3002`, then move to the next free port automatically.
46
+ Do not kill existing local servers to free `3002` during a first start. Dev, preview, and browser verification prefer `3002`, then move to the next free port only while assigning this app's first saved port. After that, normal dev/preview starts use the saved port; if that port is already serving this app, report the existing URL instead of creating a second server. A launch is successful only after the selected port serves this app's Toolcraft server identity endpoint plus the `toolcraft-app-title` marker from `index.html`; never trust a port only because some server responds there. When restarting the same app server, use `pnpm dev:restart` or `pnpm preview:restart`; restart mode reuses the saved app port and stops only the listener on that exact port before starting again, forcing it only when the soft stop does not release the port, then verifies the identity before saving/reporting the port.
@@ -14,7 +14,7 @@ Every visible product entity must prove it works. A control is not accepted beca
14
14
  - `e2e/app-performance.spec.ts`
15
15
  - `e2e/product-observable-helpers.ts`
16
16
 
17
- `pnpm verify:final` must pass before final delivery. Incremental edits use the verification tier classifier from `assembly-workflow.md`: run targeted browser acceptance for the changed entity, and add full `pnpm verify:perf` only for the first working app version or an explicit performance complaint.
17
+ `pnpm verify:final` must pass before final delivery. Incremental edits use the verification tier classifier from `assembly-workflow.md`: run targeted browser acceptance for the changed entity, and add a full browser performance checkpoint for the first working product version or an explicit performance complaint. Prefer the current AI agent's controlled browser; use `pnpm verify:perf` only as the Playwright fallback when no agent browser is available or in CI/non-agent automation.
18
18
 
19
19
  A full performance checkpoint is triggered only by the first working app version, or by a user request to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise investigate poor performance.
20
20
 
@@ -32,7 +32,7 @@ Product readiness also requires product surface: controls, layers, timeline, `ca
32
32
 
33
33
  Product apps must update `docs/toolcraft/agent-worklog.md` before final delivery. The file records why the app chose its renderer, timeline mode, layer policy, control grouping, export behavior, and performance strategy.
34
34
 
35
- The worklog must declare `Mode: product`. Every `Decision Trail` iteration must include `Request:`, `Task type:`, `User-visible result:`, `Source/reference checked:`, `Docs/contracts read:`, `Contract rules applied:`, `Decision:`, `Alternatives rejected:`, `State/output mapping:`, `Files changed:`, `Verification:`, `Skipped checks:`, and `Risks:`. `State/output mapping:` names how controls, commands, timeline, layers, media, or renderer state reaches the visible product or export. Each decision section (`Renderer`, `Timeline`, `Layers`, `Controls`, `Export`, `Performance`) must include `Decision:`, `Reason:`, and `Evidence:` entries. `Evidence` should name files, reference behavior, contract rules, browser checks, performance checks, or exact commands. `Verification` must list concrete checks such as `pnpm verify:quick`, `pnpm verify:perf`, browser tests, or Playwright scenarios. `Risks` must include either `Risk:` entries or `None:` with a reason.
35
+ The worklog must declare `Mode: product`. Every `Decision Trail` iteration must include `Request:`, `Task type:`, `User-visible result:`, `Source/reference checked:`, `Reference inputs:`, `Docs/contracts read:`, `Contract rules applied:`, `Decision:`, `Alternatives rejected:`, `State/output mapping:`, `Files changed:`, `Verification:`, `Skipped checks:`, and `Risks:`. `Reference inputs:` is the explicit inventory of prompt/reference assets for that pass: write `None` only when there were no external references, otherwise list the source apps, URLs, screenshots, videos, GIFs, screen recordings, contact sheets, extracted-frame folders, or media files used. `State/output mapping:` names how controls, commands, timeline, layers, media, or renderer state reaches the visible product or export. Each decision section (`Renderer`, `Timeline`, `Layers`, `Controls`, `Export`, `Performance`) must include `Decision:`, `Reason:`, and `Evidence:` entries. `Evidence` should name files, reference behavior, contract rules, browser checks, performance checks, or exact commands. `Performance` evidence must name the hard limit, smooth target, smooth target ratio, failed higher measurements, and attempted optimizations whenever a load profile lowers the smooth target below the hard limit. `Verification` must list concrete checks such as `pnpm verify:quick`, browser tests, the agent-browser performance checkpoint, or `pnpm verify:perf` as the Playwright fallback. First working product delivery must record `pnpm verify:final` and the browser performance checkpoint as passed, including runner `agent-browser` or `playwright-fallback`; fallback evidence must state why no agent browser was available or why the run was CI/non-agent automation. Failed, incomplete, pending, blocked, or skipped required checks make the app incomplete unless the full performance checkpoint is explicitly not required for a post-first-working non-performance edit. `Risks` must include either `Risk:` entries or `None:` with a reason.
36
36
 
37
37
  The acceptance gate fails if the worklog is missing, still says `Mode: starter`, or lacks concrete decision evidence.
38
38
 
@@ -51,14 +51,19 @@ Each row should name:
51
51
  - expected product-level observable;
52
52
  - evidence type;
53
53
  - exact `automatedTestName`;
54
- - exact `browserTestName`.
54
+ - exact `browserTestName`, the stable browser check name used by the agent-browser evidence and fallback Playwright test.
55
55
  - `controlPartCoverage` when the control is compound.
56
- - `canvasSizingCoverage: "fixed-output-size"` when `canvas.sizing.mode` is `fixed-output`.
56
+ - `canvasSizingCoverage: "fixed-output-size"` only for non-product/internal `fixed-output` fixtures.
57
+ - `canvasSizingCoverage: "intrinsic-media-size"` only for explicit media-viewer/source-native upload apps where imported media natural dimensions intentionally own `canvas.size`.
57
58
  - `persistenceCoverage: "reload"` when schema `persistence.storage` is `"localStorage"`.
58
59
 
59
60
  The test gate rejects rows without matching automated and browser test names.
60
61
 
61
- `fixed-output` canvas sizing must be deliberate. Its runtime acceptance row must explain why width, height, and aspect ratio are non-editable. A default size from the prompt should use `editable-output`, which keeps the runtime Aspect ratio, Canvas width, and Canvas height controls.
62
+ Slider and range slider rows must prove live behavior. Browser tests should drag the real thumb and assert the runtime value and product-level canvas observable update during the drag, not only after pointer release, blur, an Apply action, or a final commit. Performance-sensitive sliders still need this live acceptance; jank is handled through renderer optimization and targeted performance coverage, not by making the slider deferred by default.
63
+
64
+ `fixed-output` canvas sizing must be deliberate and is not valid for generated product/output apps with export actions. A default, reference, or fixed-format size from the prompt should use `editable-output`, which keeps the runtime Aspect ratio, Canvas width, and Canvas height controls.
65
+
66
+ `intrinsic-media` upload sizing must also be deliberate. Uploaded background/source images inside product canvases use `editable-output`, keep the current canvas size after upload, keep Setup canvas controls visible, and render cover/crop inside the current canvas bounds. Browser acceptance must upload an image with a different aspect ratio and prove the current canvas size remains unchanged while the image covers/crops the canvas.
62
67
 
63
68
  When localStorage persistence is enabled, add a runtime acceptance row that proves reload behavior. The browser test must change a real user-facing setting, wait for persistence to write, call a real page reload, and verify the restored control value or product output. Importing a settings JSON file is not persistence coverage.
64
69
 
@@ -84,6 +89,8 @@ Required parts:
84
89
 
85
90
  Testing only one sub-control is not enough. For example, a `gradient` test that changes only a stop color must fail if the app also renders Gradient type, Angle, Position, or Opacity controls.
86
91
 
92
+ Palette acceptance must also prove live behavior: selecting a family or shade updates runtime state immediately, before delayed persistence or commit timers settle, and the next canvas/product interaction uses that selected token.
93
+
87
94
  For `curves`, the acceptance row must match the intended variant. Semantic one-dimensional curves such as acceleration, bend, easing, response, depth, mask, opacity, threshold, or remap curves must set `variant: "single"` and prove `curves.points`; RGB active-channel coverage is reserved for color-correction or channel-specific curves.
88
95
 
89
96
  For `fontPicker`, product output evidence must come from actual rendered/exported product text after changing the font, weight, size, letter spacing, line height, text case, color, and opacity. Runtime value changes, selected labels, or popup font previews are preflight checks, not final acceptance.
@@ -107,7 +114,7 @@ High-confidence wrong-substitution cases:
107
114
  - segmented choices that clip instead of falling back to `select`;
108
115
  - custom controls recreating built-ins.
109
116
 
110
- `fileDrop` media-lifecycle rows must prove upload/import, clear/remove, thumbnail reorder for `multiple: true`, and global or section reset. A test that only clicks the clear button is not enough because Reset controls must also return uploaded source material to `defaultValue`.
117
+ `fileDrop` media-lifecycle rows must prove upload/import, clear/remove, image rotate/flip, thumbnail reorder for `multiple: true`, and global or section reset. A test that only clicks the clear button is not enough because Reset controls must also restore `media.defaultAssets` for predefined attached files or remove uploaded source material when no default exists. Product preview/export must consume runtime media order and `mediaAssets[].transform`.
111
118
 
112
119
  Rows that use custom controls must include `customControlCoverage` and typed `builtInFitCheck`.
113
120
 
@@ -148,11 +155,11 @@ Every app with `Export PNG` must exercise the separate `Image Export` section: c
148
155
 
149
156
  Async Export, Download, Copy, Generate, or Apply acceptance must prove the sticky footer top accent indicator is visible while the returned `onPanelAction` Promise is pending, advances when `reportProgress(0..1)` is called, and hides after it settles. Video export acceptance must prove frame-based progress updates during render/encode instead of only toggling a pending state.
150
157
 
151
- Animated app acceptance must also exercise the separate `Video Export` section: choose at least two `export.video.format` values, choose at least two `export.video.resolution` values, verify unsupported MIME/container choices fall back safely, and assert exported video bytes, dimensions, MIME/container, and duration match runtime timeline state. The duration assertion must load the exported blob as a video, wait for metadata, and compare `video.duration` with the edited timeline duration; `blobSize > 0`, `blobType`, WebM parser fallback, or assigning the expected duration when metadata is missing are not enough.
158
+ Animated app acceptance must also exercise the separate `Video Export` section: choose at least two `export.video.format` values, choose at least two `export.video.resolution` values, verify unsupported MIME/container choices fall back safely, and assert exported video bytes, dimensions, MIME/container, and duration match runtime timeline state. `current` video export must use the current canvas/output size with even encoder-safe rounding. `4k` video export must use `getToolcraftVideoExportSize`, fit inside 3840x2160, preserve aspect ratio, and produce even dimensions; do not accept PNG-style 4096px long-edge video sizing. Recorder/encoder errors must reject instead of resolving corrupt blobs. The duration assertion must load the exported blob as a video, wait for metadata, and compare `video.duration` with the edited timeline duration; `blobSize > 0`, `blobType`, WebM parser fallback, or assigning the expected duration when metadata is missing are not enough.
152
159
 
153
160
  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.
154
161
 
155
- Local `actions` acceptance must click every visible action and prove the nearby entity changed through runtime state or product output. A section-level `Randomize palette` must change palette output, `Normalize weights` must change weights/output, and `Clear selection` must clear only the scoped selection. Do not accept a test that only proves the button rendered.
162
+ Local `actions` acceptance must click every visible action and prove the nearby entity changed through runtime state or product output. A section-level `Randomize palette` must change palette output, `Normalize weights` must change weights/output, and `Clear selection` must clear only the scoped selection. Do not accept a test that only proves the button rendered. A single-button `actions` control fails validation when the control label duplicates the button label; the label must add concise context. Visual acceptance rejects side-label actions; labels sit above a two-column button grid where each button cell is 50% width.
156
163
 
157
164
  `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.
158
165
 
@@ -186,11 +193,37 @@ Acceptance rows with `product-output`, `rendered-pixels`, or `timeline-output` e
186
193
 
187
194
  Animated viewport tests must also prove that canvas drag, pan, pinch, zoom, and radar/center interactions suspend or coalesce non-essential animation preview work without changing the user's play/pause state. After the interaction, the renderer must resume from the correct timeline or autonomous time and keep canvas zoom/offset stable.
188
195
 
196
+ ## Video References
197
+
198
+ When a video, GIF, screen recording, contact sheet, or extracted-frame sequence is used as a reference, acceptance is driven by `starterTransferMode.videoReferenceStudy`.
199
+
200
+ - `storyboard` records timecoded frames with visible state and behavior observations;
201
+ - `transitionAnalysis` records frame-to-frame deltas, not only isolated frame descriptions;
202
+ - `behaviorDecomposition` states which observed behaviors must be copied;
203
+ - `acceptanceMapping` maps each observed video behavior to a real acceptance row;
204
+ - mapped acceptance rows must be automated, browser-backed, and observable in product output, timeline output, export output, or a real command side effect;
205
+ - `agent-worklog.md` records Video Reference Study evidence when `Reference inputs`, `Source/reference checked`, or `Source reviewed` cites video, GIF, screen recording, contact sheet, or extracted frames.
206
+
207
+ Do not accept a video reference implementation proved only by a single screenshot, a visual summary, generic canvas hashes, or static style checks.
208
+
209
+ ## Reference Clone
210
+
211
+ Reference clone coverage is driven by `starterTransferMode.referenceFeatureInventory`.
212
+
213
+ - `starterTransferMode.referenceStudy` records source inspection plus original/reference behavior checked by running the original or restoring it locally when possible;
214
+ - list every user-visible and output-affecting reference feature before implementation;
215
+ - include source evidence, feature-level behavior evidence from the reference study, reference behavior, Toolcraft mapping, status, and one `acceptanceId` for each item;
216
+ - map every `referenceCoverage` and `referenceTimelineCoverage` acceptance row from the inventory;
217
+ - cover canvas sizing, control mapping, renderer loop/state, pause/resume, restart, export/copy, media lifecycle, persistence/randomization/reset, and custom reference timeline behavior when those exist in the reference;
218
+ - mark behavior as `intentionally-changed` only with explicit user approval or redesign/change-request evidence.
219
+
220
+ Do not treat a few generic checks as a complete reference transfer. The acceptance set must prove that the reference functionality inventory was implemented, not merely that the app renders.
221
+
189
222
  ## Timeline And Layers
190
223
 
191
224
  When animation controls exist without `panels.timeline`, acceptance validation requires `starterTransferMode.animationIntent.mode = "autonomous"`. That intent must explain why the animation is decorative/self-running and must cover no user-facing transport, no play/pause, no scrub, no duration control, no loop control, and no export-at-time.
192
225
 
193
- Playback timeline coverage must prove play/pause, scrub, duration, loop, restart when exposed, non-looping Play at the end restarts from 0, and export/copy at selected time when relevant. Duration coverage must edit the real `Edit timeline duration` control, prove the playback range changes, and prove the renderer maps one full product animation cycle to `state.timeline.durationSeconds`. Tests should compare visible or exported output at 0, midpoint, and end after changing the timeline duration. Do not accept a renderer that uses a separate fixed local duration while the timeline displays another duration, and do not accept a renderer effect that watches `state.timeline.durationSeconds` only to dispatch `timeline.setDuration` back to a computed local value.
226
+ Playback timeline coverage must prove play/pause, scrub, duration, loop, restart when exposed, non-looping Play at the end restarts from 0, and export/copy at selected time when relevant. Timeline animation intent must match the enabled timeline mode and declare `loopDuration` with source, seconds, and evidence; `panels.timeline.defaultDurationSeconds` must match that value. Reference clones using `referenceTimeline.mode: "toolcraft-playback"` or `"toolcraft-keyframes"` must declare the same proof on `referenceTimeline.loopDuration`. Duration coverage must edit the real `Edit timeline duration` control, prove the playback range changes, and prove the renderer maps one full product animation cycle to `state.timeline.durationSeconds`. Loop coverage must prove a seamless forward-only product loop: motion advances in one direction, mirror/yoyo/ping-pong/reverse fallbacks are absent unless explicitly requested, first and last frames stitch without a visible jump, and the same seam holds after changing timeline duration. Tests should compare visible or exported output at 0, midpoint, end minus epsilon, and the wrapped first frame after changing the timeline duration. Prefer `getToolcraftTimelineLoopTime` or `getToolcraftTimelineLoopProgress` in the renderer so this phase math is shared. Do not accept a renderer that uses a separate fixed local duration while the timeline displays another duration, and do not accept a renderer effect that watches `state.timeline.durationSeconds` only to dispatch `timeline.setDuration` back to a computed local value.
194
227
 
195
228
  Keyframe timeline coverage must prove diamond creation, expanded rows, keyframe updates on control change, scrub/playback evaluation, and product output changes for every inferred keyframe-capable control. Tests must prove renderers consume typed evaluated values from the Toolcraft keyframe evaluator; checking `valueLabel`, row count, or source strings is not enough.
196
229
 
@@ -212,6 +245,6 @@ Performance browser tests must assert budgets through `expectToolcraftScenarioPe
212
245
 
213
246
  ## Fixtures
214
247
 
215
- Use fixtures that make each behavior visible. For example, background character-size controls need visible background characters, transparency needs alpha-sensitive pixels, selected-layer controls need multiple layers, timeline controls need deterministic playback or keyframe fixtures, and mode-specific controls need fixtures for every mode branch. Conditional coverage must prove visible controls, hidden controls, disabled controls, preserved values after switching away and back, and renderer output for the active branch. Count-controlled control banks must test both the low-count UI state and the expanded-count UI state; the test fails if inactive controls remain visible while the renderer ignores them.
248
+ Use fixtures that make each behavior visible. For example, background character-size controls need visible background characters, transparency needs alpha-sensitive pixels, selected-layer controls need multiple layers, timeline controls need deterministic playback or keyframe fixtures, and mode-specific controls need fixtures for every mode branch. Conditional coverage must prove visible controls, inactive controls hidden with `visibleWhen`, preserved values after switching away and back, and renderer output for the active branch. Count-controlled control banks must test both the low-count UI state and the expanded-count UI state; the test fails if inactive controls remain visible while the renderer ignores them.
216
249
 
217
250
  Generic hash differences are not enough for semantic controls. If a control promises a direction, test that direction.
@@ -18,6 +18,7 @@ No product iterations yet. When this folder becomes a product, replace this note
18
18
  - Task type:
19
19
  - User-visible result:
20
20
  - Source/reference checked:
21
+ - Reference inputs:
21
22
  - Docs/contracts read:
22
23
  - Contract rules applied:
23
24
  - Decision:
@@ -16,7 +16,7 @@ import { defineToolcraft } from "@/toolcraft/runtime";
16
16
  import { ToolcraftApp } from "@/toolcraft/runtime/react";
17
17
 
18
18
  const appSchema = defineToolcraft({
19
- canvas: { enabled: true, sizing: { mode: "intrinsic-media" }, upload: true },
19
+ canvas: { enabled: true, sizing: { mode: "editable-output" }, upload: true },
20
20
  panels: {},
21
21
  toolbar: { history: true, radar: true, theme: true, zoom: true },
22
22
  });
@@ -28,7 +28,7 @@ export function AppHome() {
28
28
 
29
29
  Routes must render `ToolcraftApp` directly. Do not compose `ToolcraftRoot`, `CanvasShell`, `ControlsPanel`, `LayersPanel`, `TimelinePanel`, or `ToolbarPanel` by hand in product routes. If a runtime surface has a performance or behavior issue, fix the shared runtime contract instead of replacing the surface with app-level UI.
30
30
 
31
- App-specific source may use only runtime extension points: schema controls, `canvasContent` for product output, `controlRenderers` for true custom controls, `onPanelAction` for sticky footer actions, and runtime commands/hooks. Do not render built-in control components such as `SliderControl`, `SelectControl`, `ColorControl`, `GradientControl`, `FontPickerControl`, `FileDropControl`, or `PanelActionsControl` directly in app code. Declare them in schema so layout, reset, history, disabled states, keyframes, labels, and tests stay runtime-owned.
31
+ App-specific source may use only runtime extension points: schema controls, `canvasContent` for product output, `controlRenderers` for true custom controls, `onPanelAction` for sticky footer actions, and runtime commands/hooks. Do not render built-in control components such as `SliderControl`, `SelectControl`, `ColorControl`, `GradientControl`, `FontPickerControl`, `FileDropControl`, or `PanelActionsControl` directly in app code. Declare them in schema so layout, reset, history, visibility, keyframes, labels, and tests stay runtime-owned.
32
32
 
33
33
  Read `appSchema.assembly` before adding custom JSX. It lists enabled surfaces, capabilities, commands, and runtime assumptions.
34
34
 
@@ -51,22 +51,24 @@ Do not leave `mode: "starter"` in a renamed product folder or after adding produ
51
51
 
52
52
  ## Control Sections
53
53
 
54
- Before writing the schema, make a Control Section Inventory. Each section needs a product entity or workflow stage, included targets, and a reason for grouping. Do not group by control type.
54
+ Before writing the schema, make and export `starterControlSectionInventory`. Each product controls section needs a product entity or workflow stage, included targets, and a reason for grouping. Do not group by control type. The exported inventory must match the schema targets exactly; if one target entity is intentionally split across sections, every split section needs `workflowStage` and `splitReason`.
55
55
 
56
56
  Bad section titles: `Controls`, `Settings`, `Options`, `Sliders`, `Inputs`, `Buttons`, `Color`, `Colors`.
57
57
 
58
58
  Good section titles name the thing being edited: `Background`, `Object`, `Square 1 (Right)`, `Token Pattern`, `Motion`, `Tone Mapping`, `Export`.
59
59
 
60
- Every app-authored controls-panel body section must have a short meaningful visible title. Runtime-created setup/settings sections use the technical title `Setup` but render without a visible heading; sticky footer action sections use the technical title `Export` but render without a visible heading.
60
+ 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.
61
61
 
62
62
  Every visible section title renders through the standard 36px collapsible header row with vertically centered text and the runtime collapse icon. Do not hand-build section headers in generated apps.
63
63
 
64
64
  Section expand/collapse uses the standard runtime height/opacity animation. Do not replace it with instant custom section visibility.
65
65
 
66
- Ordinary controls-panel body sections use 8px top spacing and 24px bottom spacing for their control content. Runtime technical `Setup` / settings sections use 12px top and bottom spacing to match side padding. Sticky footer action sections keep their dedicated spacing.
66
+ 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.
67
67
 
68
68
  If a color, slider, input, or selector edits the same entity as nearby controls, keep it in that entity section. Split only when the product has a real workflow split and cover that decision in acceptance.
69
69
 
70
+ When a selector controls branch visibility through `visibleWhen`, treat both the selector and its branch controls as one dependency group if they share the same target entity or selected branch. Keep the selector and its gated branch controls in the same section; do not create a separate section that merely mirrors one selector option unless that branch is a genuinely separate product entity with its own workflow evidence. Do not use `disabledWhen` for product branches.
71
+
70
72
  Before choosing the concrete control type for each target, check `component-rules.md` and `schema-reference.md`. Built-in compound controls must stay compound: for example, typography with font choice, weight, size, color/opacity, and text rhythm uses `fontPicker`, not a plain `select` plus separate inputs/sliders. The product renderer and acceptance rows must cover every semantic value part of the chosen component.
71
73
 
72
74
  For custom renderers, write the Renderer Technique Decision Matrix and Render Pipeline Inventory before code. The implementation plan must map every performance-sensitive control to the pass it invalidates.
@@ -84,10 +86,24 @@ Required flow:
84
86
 
85
87
  Do not implement a Figma design by eye from an image, screenshot, exported PNG, or rough visual memory. If the Figma URL is not node-specific, inspect the file/page metadata and choose the relevant node only when it is unambiguous; otherwise ask for a node-specific link.
86
88
 
89
+ ## Video References
90
+
91
+ When the prompt provides a video, GIF, screen recording, contact sheet, or extracted-frame sequence as a reference, study it as behavior before implementation. This applies to new Toolcraft apps and reference-runtime-clone work.
92
+
93
+ Write a Video Reference Study before coding. Record the inspected source, extraction method, timecoded storyboard frames, visible state in each frame, behavior inferred from each frame, frame-to-frame transition analysis, behavior decomposition, and acceptance mapping. The transition analysis must explain what changes between frames: which entities move, which anchors or state persist, what releases or retargets, what input or timeline state drives the change, and which behavior should be copied.
94
+
95
+ Do not implement a video reference from a single screenshot, a generic visual summary, or a few static style observations. If the video cannot be opened or frames cannot be extracted, stop and record the blocker instead of guessing the temporal behavior.
96
+
97
+ Declare `starterTransferMode.videoReferenceStudy` when the app uses a video reference. Each `acceptanceMapping` item must point to a real acceptance row that proves the copied behavior with automated and browser coverage. `docs/toolcraft/agent-worklog.md` must include the Video Reference Study evidence when `Reference inputs`, `Source/reference checked`, or `Source reviewed` cites a video, GIF, screen recording, contact sheet, or extracted frames.
98
+
87
99
  ## Product Output
88
100
 
89
101
  Use `canvasContent` only for product output: WebGL, Canvas 2D, SVG, DOM product text, shader previews, generated previews, export previews, or product editing handles.
90
102
 
103
+ If upload/import is part of the source-material flow, do not invent a design on the canvas before real content exists. The pre-content canvas stays neutral and runtime-backed; upload affordance belongs in `fileDrop`, not in canvas CTA text, helper copy, fake sample output, decorative placeholders, or agent-made source presets. A default procedural/reference source is allowed only when the prompt or reference explicitly defines it, and the worklog must record that evidence. If the default source is a file, image, or background image, declare it in `media.defaultAssets` with the matching `fileDrop` `sourceTarget`; it must render as an attached file that users can remove and Reset can restore.
104
+
105
+ If the uploaded image is background/source material inside the product canvas, keep the current `canvas.size` and render the image as cover/crop inside those bounds. Do not switch to `intrinsic-media`, do not resize the canvas to the image, and do not hide `Setup` canvas controls. Reserve `intrinsic-media` for explicitly justified media-viewer/source-native products with acceptance coverage.
106
+
91
107
  ```tsx
92
108
  <ToolcraftApp
93
109
  canvasContent={<ProductRenderer />}
@@ -115,15 +131,30 @@ Preserve the reference runtime as source of truth:
115
131
  - canvas sizing and media lifecycle;
116
132
  - control-to-renderer mapping.
117
133
 
134
+ Before implementation, create `starterTransferMode.referenceFeatureInventory` from the inspected reference source/runtime/UI. Include every user-visible and output-affecting behavior: controls, modes, generated objects, renderer state, media import lifecycle, canvas sizing, layers/selection, timeline/transport, export/copy, persistence, randomization, and reset behavior when present.
135
+
136
+ Each inventory item must name the reference feature, cite source evidence, cite feature-level behavior evidence from the original/restored/source-only reference study, describe the original behavior, describe the Toolcraft mapping, and point to an `acceptanceId` that proves the behavior. If behavior is intentionally changed or omitted, mark it `status: "intentionally-changed"` and cite explicit user approval or redesign/change-request evidence.
137
+
138
+ Do not rely on the user to find missing reference functionality after delivery. The port is incomplete until the inventory and acceptance coverage prove the reference functionality was reviewed and transferred.
139
+
118
140
  Toolcraft still owns the shell: schema, controls, canvas, panels, toolbar, file upload, sticky footer actions, and `canvasContent`.
119
141
 
120
142
  Do not iframe the reference, replace the route with copied original UI, or rebuild the app as a different shell.
121
143
 
144
+ Reference study is required before implementation. Declare `starterTransferMode.referenceStudy` and record:
145
+
146
+ - where the reference lives;
147
+ - which source/runtime files, routes, assets, and handlers were inspected;
148
+ - how the original was run or restored locally in the Toolcraft environment;
149
+ - which runtime/browser behaviors were checked.
150
+
151
+ Use `status: "ran-original"` when the original can run as-is. Use `status: "restored-local"` when you need to reconstruct enough of the reference inside the current environment to observe behavior. Use `status: "source-inspection-only"` only when running or restoring is blocked; include the concrete blocker and compensate with stronger source evidence and acceptance coverage.
152
+
122
153
  ## Animation Intent
123
154
 
124
155
  Before adding animation controls, write an Animation Intent Inventory. Classify the animation as playback timeline, keyframes timeline, custom reference timeline, or autonomous decorative output.
125
156
 
126
- If the user asks for product animation, use the top playback timeline by default. Use no timeline only when the animation is self-running output with no user-facing play/pause, scrub, duration, loop, restart, progress, or export-at-time behavior. In that case, declare `starterTransferMode.animationIntent.mode = "autonomous"` and list the absent transport behavior in `behaviorCoverage`.
157
+ If the product output is animated, use the top playback timeline by default. Use no timeline only when the motion is non-product autonomous decoration with no user-facing play/pause, scrub, duration, loop, restart, progress, export-at-time behavior, product animation, or video export. In that case, declare `starterTransferMode.animationIntent.mode = "autonomous"` and list the absent transport behavior in `behaviorCoverage`. When the loop period is known or product-derived, set `panels.timeline.defaultDurationSeconds` to that period and record the same value in `starterTransferMode.animationIntent.loopDuration` with source and evidence. Reference clones that use `referenceTimeline.mode: "toolcraft-playback"` or `"toolcraft-keyframes"` record the same proof in `starterTransferMode.referenceTimeline.loopDuration`. Runtime/template fallback 8s is not evidence. Product loops are seamless forward-only cycles by default: the first and last frames stitch, direction does not reverse, and mirror/yoyo/ping-pong behavior needs explicit user intent. Use `getToolcraftTimelineLoopTime` or `getToolcraftTimelineLoopProgress` in playback renderers instead of local wall-clock or fixed-duration phase math.
127
158
 
128
159
  Do not replace `TimelinePanel` with an app-level playback, transport, or timeline panel to work around performance. Playback/keyframe timeline UI is runtime-owned. Custom timeline UI is allowed only when a reference app has non-Toolcraft timeline behavior and `starterTransferMode.referenceTimeline.mode` is `"custom-reference-timeline"` with browser-backed `referenceTimelineCoverage`.
129
160
 
@@ -131,7 +162,7 @@ Animated preview renderers must prioritize viewport interactions. During canvas
131
162
 
132
163
  ## Canvas Sizing And Background
133
164
 
134
- A base/default size in the prompt is the initial output size. It does not remove user-facing size controls. Use `editable-output` unless the reference or product explicitly locks dimensions, and cover any `fixed-output` choice with `canvasSizingCoverage: "fixed-output-size"`.
165
+ A base/default, reference, or fixed-format size in the prompt is the initial output size. It does not remove user-facing size controls. Product-output, exportable, shader, procedural, and reference-clone apps use `editable-output`; keep fixed dimensions as editable `canvas.size` defaults instead of switching to `fixed-output`.
135
166
 
136
167
  Every product app exposes output background controls:
137
168
 
@@ -146,15 +177,17 @@ Every product app needs output delivery in sticky footer `panelActions`. Still-o
146
177
 
147
178
  Async product actions such as Export, Download, Copy, Generate, or Apply must return the real Promise from `ToolcraftApp onPanelAction`. The controls panel uses that Promise to show the sticky footer top accent indicator while the operation is pending. Use the `reportProgress(0..1)` callback from `onPanelAction` for determinate progress; video export reports frame-based render/encode progress, and PNG export reports phase progress for render, blob, and handoff when those phases are asynchronous. Do not fire-and-forget long export work from `onPanelAction`, and do not add custom loading strips or canvas UI for export progress.
148
179
 
149
- For complex apps, use schema `settingsTransfer: "auto"` or `true` for settings import/export. Recalculate settings-transfer eligibility after adding, removing, or reorganizing controls, sections, timeline, or layers. The runtime threshold is 12 product controls, 5 product sections, or weighted score 18. Do not put Import Settings or Export Settings in sticky footer `panelActions`; runtime inserts the technical `Setup` settings-transfer section first without a visible section heading.
180
+ Generated apps keep a controls panel so runtime `Setup` is visible from the first run. Settings import/export is mandatory runtime `Setup` behavior there; do not put Import Settings or Export Settings in sticky footer `panelActions`; runtime inserts them in the first visible headerless `Setup` controls block.
150
181
 
151
- If the app also uses `editable-output` canvas sizing, that first technical `Setup` runtime section is mandatory and contains `Export Settings`, `Import Settings`, `Aspect ratio`, `Canvas width`, `Canvas height`, and optional `Resolution scale` in that order. Do not split the canvas size fields and settings-transfer actions into app-authored sections.
182
+ If the app also uses `editable-output` canvas sizing, `Setup` contains `Export Settings`, `Import Settings`, `Aspect ratio`, `Canvas width`, `Canvas height`, optional `Resolution scale`, and optional `Timeline` in that order. Do not split the canvas size fields and settings-transfer actions into app-authored sections, and do not declare runtime Setup targets in product sections.
152
183
 
153
- For non-vector raster, Canvas 2D, WebGL, or WebGPU previews, set `canvas.renderScale: true`. Runtime appends `Resolution scale` to the same first technical section. The slider changes backing resolution from `1x` to `2x` without changing visible canvas size; DOM/SVG/vector-native previews should not use it.
184
+ For non-vector raster, Canvas 2D, WebGL, or WebGPU previews, set `canvas.renderScale: true`. Runtime appends `Resolution scale` to `Setup`. The slider changes backing resolution from `1` to `2` without changing visible canvas size; DOM/SVG/vector-native previews should not use it.
154
185
 
155
- If a controls panel shows only `Export Settings` and `Import Settings` in the first runtime section, check the canvas sizing decision. Product-output apps usually need `editable-output`; intrinsic media and explicitly fixed output are the cases where visible canvas size inputs are absent.
186
+ When `panels.timeline` is enabled, runtime appends a `Timeline` switch as the final Setup control. This is panel UI state only: off shows compact Play-only transport, on shows the extended timeline with scrubber, duration, loop, and keyframe UI. Switching it does not pause playback, remove keyframes, change export, or write product values. If `panels.timeline` is omitted, the Timeline switch must not appear.
156
187
 
157
- For user-edited settings that should survive reload, use schema `persistence` with a stable app-specific key. When localStorage persistence is enabled, acceptance must prove a user setting restores after a real browser reload. Do not use settings import/export as a workaround for broken persistence.
188
+ If a controls panel shows only `Export Settings` and `Import Settings` in the first runtime section, check the canvas sizing decision. Product-output apps need `editable-output`; only intrinsic media and non-product/internal fixed fixtures should omit visible canvas size inputs. Adding app-authored Canvas width/height controls elsewhere is not an alternative.
189
+
190
+ For user-edited settings that should survive reload, use schema `persistence` with a stable app-specific key. When localStorage persistence is enabled, acceptance must prove a user setting restores after a real browser reload. Include `"media"` only when runtime media state itself should survive reload, such as predefined attached files that can be removed, reordered, or transformed. Do not use settings import/export as a workaround for broken persistence.
158
191
 
159
192
  Every app with `Export PNG` must include a separate `Image Export` controls section with:
160
193
 
@@ -163,16 +196,16 @@ Every app with `Export PNG` must include a separate `Image Export` controls sect
163
196
 
164
197
  `Image Export` `Format` and `Resolution` are one compact workflow pair: render them in a two-column inline row by default. For still-output apps, place `Image Export` directly above sticky footer export buttons. For animated apps with both image and video export, place `Image Export` immediately before `Video Export`.
165
198
 
166
- Animated apps with `Export Video` must include a separate `Video Export` controls section with at least:
199
+ Animated apps with `Export Video` must enable the top Toolcraft timeline and include a separate `Video Export` controls section with at least:
167
200
 
168
201
  - `export.video.format` as `select`, defaulting to `mp4`, with `mp4` and `webm` baseline options;
169
202
  - `export.video.resolution` as `select`, defaulting to `current`, with options such as `current` and `4k`.
170
203
 
171
204
  Place `Video Export` as the final authored controls section directly above sticky footer export buttons. Treat `Format` and `Resolution` as a compact semantic pair and put them in one two-column inline row by default. Use vertical rows only when the compact row would clip labels or selected values, and record that fallback reason in the worklog.
172
205
 
173
- Use standard export helpers. `createToolcraftPngExportCanvas` accepts `includeBackground` for runtime PNG transparency and `resolution` for image-export output size. `shouldIncludeToolcraftPreviewBackground(state)` controls live preview product-background visibility. Pass the selected `export.image.resolution` into the PNG helper so 2K/4K/8K produce actual 2048/4096/8192px long-edge PNGs. Do not rely on static `export.png.background` alone when the UI exposes background controls. Video export keeps background and still uses `getToolcraftRetinaExportSize`.
206
+ Use standard export helpers. `createToolcraftPngExportCanvas` accepts `includeBackground` for runtime PNG transparency and `resolution` for image-export output size. `shouldIncludeToolcraftPreviewBackground(state)` controls live preview product-background visibility. Pass the selected `export.image.resolution` into the PNG helper so 2K/4K/8K produce actual 2048/4096/8192px long-edge PNGs. Do not rely on static `export.png.background` alone when the UI exposes background controls. Video export keeps background and uses `getToolcraftVideoExportSize` for `current` and `4k` dimensions.
174
207
 
175
- Video export must choose the actual MIME/container with `MediaRecorder.isTypeSupported(...)` or an explicit encoder/transcoder capability check. `MOV` and `ProRes` are allowed only when the app provides a custom encoder/transcoder and proves it with acceptance plus performance coverage. Treat `4K` as an export resolution target, not a hardcoded canvas lock. Offline rendered-frame export must encode or mux frame timestamps from runtime timeline time; real-time `canvas.captureStream()` plus `MediaRecorder` records wall-clock export time and is not enough when renderer work can be slower than playback. Browser acceptance must load the exported blob as a video, wait for metadata, and compare `video.duration` with the edited timeline duration; `blobSize > 0`, `blobType`, parser fallback, or assigning the expected duration in `catch` is not enough.
208
+ Video export must choose the actual MIME/container with `MediaRecorder.isTypeSupported(...)` or an explicit encoder/transcoder capability check. `MOV` and `ProRes` are allowed only when the app provides a custom encoder/transcoder and proves it with acceptance plus performance coverage. Treat `4K` as an export resolution target, not a hardcoded canvas lock and not PNG-style 4096px long-edge sizing. `getToolcraftVideoExportSize` keeps `current` at the current canvas/output size with even encoder-safe rounding, and keeps `4k` encoder-safe by fitting inside 3840x2160, preserving aspect ratio, and returning even dimensions. Set recording canvas dimensions before `captureStream`, `MediaRecorder`, `VideoEncoder`, or equivalent setup, and reject recorder/encoder errors instead of returning corrupt blobs. Offline rendered-frame export must encode or mux frame timestamps from runtime timeline time; real-time `canvas.captureStream()` plus `MediaRecorder` records wall-clock export time and is not enough when renderer work can be slower than playback. Browser acceptance must load the exported blob as a video, wait for metadata, and compare `video.duration` with the edited timeline duration; `blobSize > 0`, `blobType`, parser fallback, or assigning the expected duration in `catch` is not enough.
176
209
 
177
210
  ## Verification Tiers
178
211
 
@@ -193,18 +226,20 @@ Use these tiers:
193
226
  | Tier 1 — local control presentation | One control or panel visual state changes: spacing, hover, focus, disabled, marker visibility, label fit, or component variant display. Runtime state shape and product renderer are unchanged. | Targeted unit/component test plus one focused browser check for the affected control or panel. |
194
227
  | Tier 2 — schema/product behavior | Controls, sections, defaults, persistence, panel actions, export actions, acceptance rows, or product behavior mapping changes. | `pnpm verify:quick` plus relevant browser acceptance. Run perf only when the changed control affects renderer workload or responsiveness. |
195
228
  | Tier 3 — renderer/canvas/runtime feature | Custom renderer, animation loop, canvas sizing, upload/media, timeline, layers, toolbar, export bytes, WebGL/Canvas/SVG output, zoom, radar, history, heavy control behavior changes, or a post-generation iteration that touches renderer workload or viewport stability. | `pnpm verify:quick`, targeted browser acceptance, and targeted performance scenarios only for touched workload/viewport/export paths. |
196
- | Tier 4 — final delivery/template architecture | Fresh generated app completion, folder export, commit-ready delivery, dependency changes, runtime/template/contract/CLI changes, broad refactors, or major post-generation iterations that rewrite renderer, canvas, animation, timeline/keyframes, layers, media, export, or control mapping. | Fresh folders run `pnpm install` once, then `pnpm verify:final`; add `pnpm verify:perf` only for the first working app version or explicit performance complaints, then start `pnpm dev` to provide the local URL. |
229
+ | Tier 4 — final delivery/template architecture | Fresh generated app completion, folder export, commit-ready delivery, dependency changes, runtime/template/contract/CLI changes, broad refactors, or major post-generation iterations that rewrite renderer, canvas, animation, timeline/keyframes, layers, media, export, or control mapping. | Fresh folders run `pnpm install` once, then `pnpm verify:final`; for the first working product version also run and pass a browser performance checkpoint with the current AI agent's controlled browser when available, using `pnpm verify:perf` only as fallback, then start `pnpm dev` to provide the local URL. |
197
230
 
198
231
  Choose the tier by blast radius, not by line count. If uncertain, move one tier higher, not automatically to Tier 4.
199
232
 
200
233
  Do not rerun `pnpm install` after every edit. Run it after fresh export, dependency changes, lockfile changes, or a missing package error.
201
234
 
202
- Use `pnpm verify:ui` when a tier calls for the browser acceptance suite without the performance suite. Use a focused named Playwright test instead when only one entity changed and the relevant test is already known.
235
+ Use `pnpm verify:ui` when a tier calls for the browser acceptance suite without the performance suite. Use the agent-controlled browser for focused checks when available; use a focused named Playwright test only as fallback when no agent browser is available or the relevant CI/non-agent check is already known.
203
236
 
204
- Run a full performance checkpoint with `pnpm verify:perf` only when the first working version of the app exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance.
237
+ Run a full performance checkpoint only when the first working version of the app exists, or when the user explicitly asks to optimize performance, fix lag, remove jank, speed up animation, stabilize drag/zoom, or otherwise complains about performance. Prefer the agent-controlled browser; use `pnpm verify:perf` only as the Playwright fallback.
205
238
 
206
239
  Feature loops after the first working version do not run the full performance suite by default. Renderer, canvas, animation, export, timeline, layers, `canvas.renderScale`, bug fixes, and performance-sensitive controls still need targeted functional/browser checks first, plus targeted performance scenarios only when they directly exercise the touched path. Record any skipped full performance run and reason in the worklog.
207
240
 
241
+ The app is not complete when required checks are failed, incomplete, pending, blocked, or listed as skipped. First working product delivery must record `pnpm verify:final` and the browser performance checkpoint as passed in the worklog, including runner `agent-browser` or `playwright-fallback`. After the first working version, skipping the full performance suite is valid only when the worklog explicitly says the full performance checkpoint is not required for a post-first-working non-performance edit.
242
+
208
243
  For final delivery, run:
209
244
 
210
245
  ```bash
@@ -212,6 +247,6 @@ pnpm verify:final
212
247
  pnpm dev
213
248
  ```
214
249
 
215
- Browser verification must use the real Toolcraft shell plus renderer output. `pnpm verify:final` runs the full static, build, and browser functional gate. `pnpm verify:perf` is intentionally separate and only runs for the two full-performance triggers. `pnpm dev` is intentionally separate because it keeps the local server running.
250
+ Browser verification must use the real Toolcraft shell plus renderer output. `pnpm verify:final` runs the full static, build, and browser functional gate. The browser performance checkpoint is intentionally separate and only runs for the two full-performance triggers; `pnpm verify:perf` is the Playwright fallback command for that checkpoint. `pnpm dev` is intentionally separate because it keeps the local server running.
216
251
 
217
- Do not stop existing local servers to free `3002`. `pnpm dev`, `pnpm preview`, and browser verification prefer `3002`, then automatically use the next free port when it is occupied.
252
+ Do not stop existing local servers to free `3002` during a first start. `pnpm dev`, `pnpm preview`, and browser verification prefer `3002`, then automatically use the next free port only while assigning the app's first saved port. After that, normal dev/preview starts use the saved port; if that port already serves the same app, report the existing URL instead of creating a second server. A launch is valid only after the selected port serves the current app root through the Toolcraft server identity endpoint and the app title marker from `index.html`; a random listener on that port is not enough. When restarting an app server you already started, use `pnpm dev:restart` or `pnpm preview:restart`; restart mode reuses the previously saved app port, stops the listener on that exact port if needed, force-stops it if the port is still occupied, starts on the same port again, and verifies the same app identity before saving/reporting the port.