@pixel-point/toolcraft 0.0.13 → 0.0.14
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.test.mjs +49 -6
- package/templates/starter/AGENTS.md +4 -3
- package/templates/starter/docs/toolcraft/README.md +15 -0
- package/templates/starter/docs/toolcraft/acceptance-testing.md +2 -0
- package/templates/starter/docs/toolcraft/assembly-workflow.md +35 -171
- package/templates/starter/docs/toolcraft/component-rules.md +12 -188
- package/templates/starter/docs/toolcraft/core/control-selection.md +93 -0
- package/templates/starter/docs/toolcraft/core/layout.md +104 -0
- package/templates/starter/docs/toolcraft/core/media-upload.md +85 -0
- package/templates/starter/docs/toolcraft/core/performance.md +83 -0
- package/templates/starter/docs/toolcraft/core/reference-study.md +115 -0
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +53 -0
- package/templates/starter/docs/toolcraft/core/setup-export.md +86 -0
- package/templates/starter/docs/toolcraft/core/timeline-animation.md +67 -0
- package/templates/starter/docs/toolcraft/custom-controls.md +2 -0
- package/templates/starter/docs/toolcraft/performance.md +2 -0
- package/templates/starter/docs/toolcraft/renderer-technique.md +2 -0
- package/templates/starter/docs/toolcraft/schema-reference.md +117 -367
- package/templates/starter/docs/toolcraft/workflow.md +12 -10
- package/templates/starter/scripts/check-toolcraft-docs.mjs +28 -6
- package/templates/starter/src/app/starter-acceptance.test.ts +9 -8
|
@@ -1,48 +1,14 @@
|
|
|
1
1
|
# Component Rules
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Choose controls by product value model before UI appearance.
|
|
6
|
-
|
|
7
|
-
- Exact owner: if the value model belongs to a built-in, use that built-in.
|
|
8
|
-
- Best fit: if multiple built-ins can work, choose one and record the reason.
|
|
9
|
-
- Custom escape hatch: use custom controls only after documenting checked built-ins and why the closest one is insufficient.
|
|
10
|
-
|
|
11
|
-
If a built-in owner is discovered after a custom workaround, replace the workaround with the built-in.
|
|
12
|
-
|
|
13
|
-
Common exact-owner choices:
|
|
3
|
+
> Reading route: start with `workflow.md`. Core generated-app rules live in `core/*`; this file is a focused component reference for the topic below.
|
|
14
4
|
|
|
15
|
-
|
|
16
|
-
- Use `fontPicker` for typography that includes font family, weight, size, text case, text color/opacity, letter spacing, or line height.
|
|
17
|
-
- Use `colorOpacity` when one product entity owns both color and opacity.
|
|
18
|
-
- Use `rangeSlider` or `rangeInput` for lower/upper bounds or from/to ranges.
|
|
19
|
-
- Use `curves` for editable tone, response, easing, remapping, opacity, depth, mask, or channel curves.
|
|
20
|
-
- Use `vector` for position, offset, direction, focus, anchor, light direction, or color-balance pads.
|
|
21
|
-
- Use `fileDrop` for source material uploads.
|
|
22
|
-
- Use `imagePicker` for choosing one visual option from a set.
|
|
23
|
-
- Use `palette` only for constrained design-token color choices with both family and shade: brand palette, Tailwind-like token color, style-guide color scale, semantic palette family, or theme accent token.
|
|
24
|
-
- Use `actions` for local section commands that affect only the nearby entity, such as randomize palette, normalize weights, sort glyphs, clear selection, duplicate item, or reset current stop.
|
|
25
|
-
- Use `collectionActions` for repeatable product entities whose actual item list can grow or shrink, such as colors, glyphs, symbols, points, rules, variants, object entries, or typography style entries. Use it instead of a count slider when the user edits the actual set. The item list must be runtime state that changes preview/export, not panel-only row chrome. The collection control shows the collection `label` on the left and remove/add icon buttons on the right. Homogeneous repeated items do not show visible per-item labels like `Color 1`, `Color 2`, `Item 1`, or `Item 2` when the collection label already names the group. Item controls should use built-ins such as `color`, `colorOpacity`, `text`, `select`, `segmented`, `slider`, `switch`, `checkbox`, `rangeInput`, or `fontPicker` before any custom renderer. Use `fontPicker` as the item control when each item is a text style or typography entity; do not split its owned fields into neighboring collection controls.
|
|
26
|
-
- For a single `actions` button, the control label and the button label must not be identical. Keep the button as the command verb and make the control label a concise one- or two-word context such as `Ink wash`, `Palette action`, or `Current layer`.
|
|
27
|
-
- If an `actions` control has a visible label, the label is always above the buttons. Do not use a side-label layout with buttons on the right.
|
|
28
|
-
- Actions render in 50% cells: one button uses the left half, two buttons fill one row, and larger groups continue in two columns.
|
|
29
|
-
- Do not stretch an odd trailing action full-width or center it; keep it in the left 50% cell.
|
|
30
|
-
- Use `panelActions` for sticky final product actions such as export, copy, generate, apply, or download.
|
|
31
|
-
|
|
32
|
-
When upload/import is part of the source-material flow, `fileDrop` owns the empty/upload state. Do not put a custom pre-upload design, CTA, helper copy, fake sample output, decorative placeholder, or agent-made source preset on the canvas. A default procedural/reference source is allowed only when the prompt or reference explicitly defines it and the worklog records that evidence. If the default source is a file, image, or background image, declare it in `media.defaultAssets` with `sourceTarget` matching the `fileDrop` control so it renders as an attached file rather than a hidden renderer constant.
|
|
33
|
-
|
|
34
|
-
Small action buttons inside custom controls are for item-level actions such as remove, reorder, add stop, or delete stop. Use schema `actions` for section-level local commands. Keep final product actions in `panelActions`, keep timeline transport in the top timeline, and keep global reset in the controls panel header.
|
|
5
|
+
## Control Decision Catalog
|
|
35
6
|
|
|
36
|
-
|
|
7
|
+
Use `core/control-selection.md` for the built-in fit check, exact control owners, compound-control ownership, actions, collection actions, vector ownership, and the custom control gate.
|
|
37
8
|
|
|
38
9
|
## Dividers
|
|
39
10
|
|
|
40
|
-
-
|
|
41
|
-
- Large built-in compound controls inside a section render content-width internal dividers only when their parent section contains more than one visible control item. Keep 18px between each rendered internal divider and the compound control content. If the compound control is the first item in that section, render only its bottom internal divider and remove the top internal padding. If it is the last item, render only its top internal divider and remove the bottom internal padding. This applies to `gradient`, `fontPicker`, RGB `curves`, `channelMixer`, and `palette`. Single `curves` are one labeled control and do not render internal dividers.
|
|
42
|
-
- If a section contains exactly one control, whether simple or compound, render only the parent section dividers.
|
|
43
|
-
- Do not add full-width borders inside a compound control, and do not put dividers only around an internal subsection such as Gradient Stops.
|
|
44
|
-
- Small compound fields such as `colorOpacity` and `rangeInput` stay inline fields without section dividers.
|
|
45
|
-
- `collectionActions` is a compound control when it shares a section with generated item controls, so it follows the same content-width divider rules. Place it at the start of the controlled section. Generated item controls still follow normal density rules: plain colors use equal 50% columns when they fit, while color+opacity items stay stacked.
|
|
11
|
+
Use `core/layout.md` for section dividers and compound-control divider rules. Component-specific exceptions are documented in the relevant component sections below.
|
|
46
12
|
|
|
47
13
|
## Sliders
|
|
48
14
|
|
|
@@ -102,71 +68,21 @@ Standalone `select` controls render stacked and full-width: label above, dropdow
|
|
|
102
68
|
|
|
103
69
|
Use a two-column inline row only for related short `select` pairs that tune one workflow or entity, such as export `Format` and `Resolution`. If either label or selected value clips, truncates, or loses internal padding, stack the pair and record the fit reason.
|
|
104
70
|
|
|
105
|
-
##
|
|
106
|
-
|
|
107
|
-
Slider and range slider controls are live canvas controls. Dragging a thumb must update runtime state and product output while the drag is in progress, not only on pointer release, blur, an Apply action, or a final commit. Browser acceptance should drag the real control and prove the canvas/product observable changes during the interaction.
|
|
71
|
+
## Slider Responsiveness
|
|
108
72
|
|
|
109
|
-
|
|
73
|
+
Use `core/performance.md` for live slider responsiveness, renderer optimization, and browser evidence requirements.
|
|
110
74
|
|
|
111
75
|
## Sections
|
|
112
76
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Section splitting must preserve dependency cohesion. A selector that chooses a mode, type, source, variant, or include state stays with the controls it gates when they share the same product entity. Prefer internal compound-control dividers, tighter labels, or a more specific section title before moving a gated branch into a separate section.
|
|
116
|
-
|
|
117
|
-
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. Do not omit a title on app-authored body sections to avoid naming decisions; choose the nearest honest product context instead.
|
|
118
|
-
|
|
119
|
-
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.
|
|
120
|
-
|
|
121
|
-
Section expand/collapse uses the standard runtime height/opacity animation. Do not replace it with instant custom section visibility.
|
|
122
|
-
|
|
123
|
-
Section collapsed/expanded state persists as a per-app runtime UI preference. It is not undo/redo state, not settings import/export state, and `Reset controls` must not clear it. Runtime `Setup` is not collapsible; sticky footer `Export` sections are not collapsible.
|
|
124
|
-
|
|
125
|
-
Ordinary section headers expose the runtime section reset action before the collapse button. It dispatches `controls.resetTargets` and restores only that section's control targets to their schema `defaultValue`.
|
|
126
|
-
|
|
127
|
-
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.
|
|
77
|
+
Use `core/layout.md` for section grouping, dependency cohesion, headers, reset, collapse persistence, spacing, dividers, labels, inline rows, and color-row fit. Keep this page focused on component-specific behavior.
|
|
128
78
|
|
|
129
79
|
## Colors
|
|
130
80
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
Keep color inside a section when it configures the same entity as nearby controls. Use a standalone color section only when color is the whole semantic section.
|
|
134
|
-
|
|
135
|
-
Standalone color section titles must describe product role. Never generate a section titled `Color` or `Colors`. If no meaningful role exists, use a neutral title such as `Appearance` instead of omitting the title.
|
|
136
|
-
|
|
137
|
-
Decide color label visibility from the user's point of view and apply that decision to the whole semantic group. Omit per-item labels such as `Color 1`, `Color 2`, or `Color 3` when the colors only add variety to one shared palette/color bank such as `Accent Shades`, `Bead Colors`, or `palette.accent1..5`, even if sibling controls like `Spread`, `Mix`, or `Randomness` tune distribution. Do not mix labeled and unlabeled items inside one semantic color bank. Keep visible labels when each color edits a distinct user-facing entity or role, such as `Fill`, `Stroke`, `Background`, `Connector`, `Object`, or `Highlight`.
|
|
138
|
-
|
|
139
|
-
Multiple related plain colors stay in the same section and render at most two per row. If the bank has an odd trailing plain `color`, the last color still keeps the same half-width footprint instead of stretching to a full row. If any color control has opacity, keep it stacked instead of placing it in a two-column row.
|
|
140
|
-
|
|
141
|
-
Use `colorOpacity` when one product entity owns both color and opacity, such as text color, shadow color, glow color, overlay color, or stroke color. Do not split that into a separate `color` plus opacity slider/input.
|
|
142
|
-
|
|
143
|
-
When one short numeric/text field and one plain `color` field configure the same entity, they can share a two-column inline row. Example: `Mask size` and `Color` belong in the same `Mask` row instead of two stacked rows. Do not put `colorOpacity` in inline rows.
|
|
144
|
-
|
|
145
|
-
Mixed inline rows usually require label parity: every field in that row has a visible label. Toggle-plus-parameter rows are the section-owned exception: keep the `switch`/`checkbox` label visible and set the non-toggle parameter to `label: false`; if the parameter label is needed, stack the controls instead. All 50/50 inline rows use the same horizontal column gap as paired `select` controls; do not give toggle-plus-parameter rows a separate wider or narrower gap. The required `Background` section row uses the switch label `Include` beside the background color parameter with `label: false`. Palette variation color banks are the other exception when the group or section label already names the color bank.
|
|
146
|
-
|
|
147
|
-
Renderer-owned output background is a base product control. Use a schema `color` target such as `appearance.background` or `scene.background`, add an `export.includeBackground` control for PNG transparency, and make preview/export read those runtime values. Keep them in one required `Background` section directly before the first export settings section. With PNG export, that first section is `Image Export`; with video-only export, it is `Video Export`. Use one equal-width inline row with `export.includeBackground` on the left and `appearance.background` on the right when no other fit rule is violated. The switch label is `Include`, not `Include background`; the background color control uses `label: false`. Each control occupies one half of the row; do not shrink the toggle column to intrinsic width. `export.includeBackground` controls PNG alpha and live preview product-background visibility through `shouldIncludeToolcraftPreviewBackground(state)`; it must not make the Toolcraft canvas shell/backing or video output transparent. Do not hardcode a configurable background in CSS, Canvas `fillStyle`, or WebGL clear color.
|
|
81
|
+
Use `core/layout.md` for semantic color grouping, color labels, row fit, and color/opacity layout. Use `core/setup-export.md` for the required output `Background` section and export background behavior.
|
|
148
82
|
|
|
149
83
|
## File Upload
|
|
150
84
|
|
|
151
|
-
Use `
|
|
152
|
-
|
|
153
|
-
Use `assetKind: "image"` for image-only source uploads and `assetKind: "file"` for arbitrary uploaded files. Image mode accepts images only by default. File mode accepts any file by default unless `accept` narrows the allowed extensions or MIME types.
|
|
154
|
-
|
|
155
|
-
In single-layer apps, the runtime shows uploaded image preview and clear button in the file control. Clearing removes the attached source from the renderer and canvas. Global Reset controls and section reset restore `media.defaultAssets` for that fileDrop target; when no default asset exists, reset removes uploaded source material and returns the fileDrop target to `defaultValue`. If users can delete/reorder/transform predefined attached files and that state should survive reload, include `"media"` in schema persistence.
|
|
156
|
-
|
|
157
|
-
In image mode, the runtime owns image transform actions directly below the uploader: `90° Right`, `Flip horizontal`, and `Flip vertical`. They render through the built-in actions-control in one three-column row with compact visible labels: `90°`, `Flip H`, `Flip V`; keep a 6px vertical gap between the uploader and action row. Do not create a custom image action button grid. With exactly one uploaded image, those actions are visible immediately. With multiple uploaded images, the user selects a thumbnail first; until then the actions are hidden, and once shown they apply only to the selected image. Product preview/export must consume `state.mediaAssets[].transform` rather than keeping separate image transform state.
|
|
158
|
-
|
|
159
|
-
The FileDrop panel preview is not product canvas rendering. It keeps a stable preview frame across rotate/flip actions and contains the transformed bitmap inside that frame, so horizontal or vertical uploads are never cropped by the control preview. Canvas/product renderers may still use cover/crop when the uploaded image is source material.
|
|
160
|
-
|
|
161
|
-
Use `multiple: true` when the app needs several uploaded images as one source set. The runtime appends media, switches to a sortable four-column thumbnail grid when more than one image is present, puts the add-more tile last, and keeps per-image removal inside the file control. Dragging thumbnails updates runtime media order; preview, export, and renderer mapping must consume that order instead of keeping a separate product-only order.
|
|
162
|
-
|
|
163
|
-
In file mode, uploaded files render as a sortable list with a paperclip icon, filename, remove button, and `--border/5` separators. Do not build custom file lists, custom upload buttons, or custom sorting for generic source files when `fileDrop` can represent the source set.
|
|
164
|
-
|
|
165
|
-
When an app contains both image and file uploaders, canvas drops route by asset kind. Image files prefer visible image uploaders; non-image files prefer visible file uploaders; file uploaders may accept images only when no image uploader matches. Product renderers must consume `state.mediaAssets` filtered by `sourceTarget` and runtime media order.
|
|
166
|
-
|
|
167
|
-
When uploaded images are used as canvas/background source material, use `editable-output`, draw them with cover/crop behavior, scale proportionally until the current canvas bounds are fully covered, leave canvas dimensions and Setup controls unchanged, and crop overflow at the canvas bounds.
|
|
168
|
-
|
|
169
|
-
In multi-layer apps, deletion and visibility belong to the Layers panel; `fileDrop` stays an upload target.
|
|
85
|
+
Use `core/media-upload.md` for `fileDrop` ownership, image/file modes, multiple uploads, sorting, transform actions, canvas source images, default assets, and layer ownership.
|
|
170
86
|
|
|
171
87
|
## Image Picker
|
|
172
88
|
|
|
@@ -256,23 +172,7 @@ Use `code` / `CodeTextarea` as the base multiline content editor for any potenti
|
|
|
256
172
|
|
|
257
173
|
## Labels
|
|
258
174
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
Short labels must still be semantically sufficient with nearby context. `Animation` / `Speed` is fine because the section names the entity; `Settings` / `Speed` should become `Animation speed`, and mixed visual buckets should use labels such as `Symbol color` or `Background opacity`.
|
|
262
|
-
|
|
263
|
-
Visible control labels can get a runtime-owned filled Phosphor question tooltip icon. Put a concise product-specific explanation in `description` only when it adds meaning beyond the label. Do not write recaps like `Adjusts Opacity`, and do not build custom help icons beside built-in labels.
|
|
264
|
-
|
|
265
|
-
Do not add `description` to obvious color clusters. If a section title already names the palette/color context, sequential labels such as `Color 1`, `Color 2`, or simple palette controls such as `Spread` do not need help icons. Keep the whole obvious group clean unless the tooltip explains a non-obvious product behavior.
|
|
266
|
-
|
|
267
|
-
For compound controls such as `fontPicker`, `description` must not enumerate owned fields like font, weight, size, case, color, opacity, letter spacing, or line height. The component already labels those fields.
|
|
268
|
-
|
|
269
|
-
If a source label is unavoidably long, keep the visible label concise and rely on native `title` for the full text.
|
|
270
|
-
|
|
271
|
-
Switch and checkbox labels name the setting context, not the action. Do not prefix them with `Enable` or `Disable`; use `CRT`, `Glow`, `Loop`, or `Guides` instead of `Enable CRT` or `Disable guides`. If the section title already names the setting context, do not repeat that title as the visible toggle label; use a short contextual label such as `Include` or, only for icon-only visual toggles, `label: false` with the meaning in `target` and `description`.
|
|
272
|
-
|
|
273
|
-
Two adjacent `switch` or `checkbox` controls for the same product entity must share one inline row when every visible label fits without truncation. Use short one- or two-word labels such as `Snap X` and `Snap Y`, or `Glow` and `Loop`. The runtime auto-pairs safe adjacent toggles by target entity; use explicit layout groups only when pairing a toggle with a non-toggle parameter. If either label would truncate in half-width, remove the inline group and let the toggles stack.
|
|
274
|
-
|
|
275
|
-
A single `switch` or `checkbox` may share an inline row with one related parameter control when the toggle label fits and the controls edit the same entity. This row is always equal-width: each control occupies one half, using the same horizontal column gap as a paired `select` row. The non-toggle parameter uses `label: false`; if that parameter label is needed for clarity, stack the controls instead. Example: `Loop` plus an unlabeled duration field, or `Include` plus unlabeled background color inside the required `Background` section. If the section title already names the toggle context, shorten the toggle label instead of repeating the title.
|
|
175
|
+
Use `core/layout.md` for label naming, help tooltip eligibility, switch/checkbox naming, toggle rows, and label parity. Component pages should add `description` only for non-obvious product behavior that the core layout rules allow.
|
|
276
176
|
|
|
277
177
|
## Layers
|
|
278
178
|
|
|
@@ -284,87 +184,11 @@ When Layers are enabled, browser tests must use the real LayersPanel UI: select,
|
|
|
284
184
|
|
|
285
185
|
## Timeline
|
|
286
186
|
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
- `timeline-playback`: user-facing play, pause, scrub, duration, loop, restart, progress, export-at-time, or video export.
|
|
290
|
-
- `timeline-keyframes`: editable diamonds, rows, easing, or keyframe evaluation.
|
|
291
|
-
- `autonomous`: decorative or self-running output with no user-facing transport and no video export.
|
|
292
|
-
|
|
293
|
-
Product output animation uses the top Toolcraft timeline. Use no timeline only for non-product autonomous decorative/self-running motion without video export, and declare `starterTransferMode.animationIntent.mode = "autonomous"` with coverage proving no play/pause, scrub, duration, loop, export-at-time, product animation, or video export behavior.
|
|
294
|
-
|
|
295
|
-
Use playback timeline for play, pause, scrub, duration, loop, restart, export-at-time, or video export.
|
|
296
|
-
|
|
297
|
-
When `panels.timeline` is enabled for a new Toolcraft app, `starterTransferMode.animationIntent` must match it: `mode: "timeline-playback"` for playback, or `mode: "timeline-keyframes"` for keyframes.
|
|
298
|
-
|
|
299
|
-
Playback renderers must read `state.timeline.currentTimeSeconds`, `state.timeline.durationSeconds`, `state.timeline.isPlaying`, and loop state from the runtime. The full animation cycle must span `state.timeline.durationSeconds`; do not hard-code a separate local animation duration such as 3s or 8s inside the renderer.
|
|
300
|
-
|
|
301
|
-
Product animation loop means a seamless forward-only cycle by default. Motion advances in one direction, the first and last frames stitch without a visible jump, and mirror, yoyo, ping-pong, or reverse loops are allowed only when the user explicitly requests that behavior as a product mode.
|
|
302
|
-
|
|
303
|
-
When the product has a known loop duration, declare it as `panels.timeline.defaultDurationSeconds`; the runtime timeline starts from that loop duration instead of an unrelated 8s default. Timeline animation intent must also declare `loopDuration` with `source`, `seconds`, and `evidence`. Valid sources are `reference`, `user-request`, and `product-derived`; runtime/template fallback 8s is not a valid source. `panels.timeline.defaultDurationSeconds` must match `animationIntent.loopDuration.seconds` so the initial timeline UI shows the declared product loop. Renderers may compute an initial loop duration default during app initialization or reset, but they must not watch `state.timeline.durationSeconds` and dispatch `timeline.setDuration` back to a computed local value. Once the user edits the timeline duration, that runtime value is the loop duration source of truth and renderer progress must map into it. Use `getToolcraftTimelineLoopTime` or `getToolcraftTimelineLoopProgress` to derive loop phase from `state.timeline.currentTimeSeconds` and `state.timeline.durationSeconds`; do not hand-roll wall-clock, fixed-duration, mirror, yoyo, ping-pong, or reverse phase math. Changing duration must preserve seamless forward-loop semantics: one complete cycle maps from `0` to `state.timeline.durationSeconds`, the first and last frames still stitch, direction does not reverse, and the renderer must not switch to wall-clock time or a fixed local duration.
|
|
304
|
-
|
|
305
|
-
For reference-runtime-clone apps that map reference transport to the Toolcraft timeline, the same duration proof lives on `starterTransferMode.referenceTimeline.loopDuration`. `referenceTimeline.mode: "toolcraft-playback"` or `"toolcraft-keyframes"` must declare `loopDuration` with source, seconds, and evidence, and `panels.timeline.defaultDurationSeconds` must match it. Do not let a reference clone inherit the runtime/template 8s default unless the reference or user request actually proves an 8s loop.
|
|
306
|
-
|
|
307
|
-
Use keyframes timeline for diamonds, editable rows, easing, or keyframe evaluation. In keyframes mode, Toolcraft infers capable controls; do not manually hide diamonds on controls that can be keyframed.
|
|
308
|
-
|
|
309
|
-
Keyframe state stores typed control values. `valueLabel` is display-only for the timeline UI; renderers and tests must never parse it as the source of truth. Custom renderers must read keyframed settings through `evaluateToolcraftTimelineValues`, `evaluateToolcraftTimelineValue`, `useToolcraftEvaluatedValues`, or `useToolcraftEvaluatedValue` instead of reading raw `state.values` for keyframed targets.
|
|
310
|
-
|
|
311
|
-
Playback-only timelines stay collapsed and must not show control diamonds or expanded keyframe rows.
|
|
312
|
-
|
|
313
|
-
When non-looping playback reaches the end, pressing Play again must restart from time 0. Do not require users to scrub back manually before replaying.
|
|
314
|
-
|
|
315
|
-
App-wide Play, Pause, Animate, and Restart controls do not belong in the right panel.
|
|
316
|
-
|
|
317
|
-
Right-panel animation controls may tune renderer parameters such as mode, intensity, speed, or stagger only after the animation intent is declared. They must not replace top timeline transport.
|
|
318
|
-
|
|
319
|
-
Do not replace `TimelinePanel` with an app-level playback, transport, or timeline panel to avoid runtime performance issues. Keep the runtime panel design and fix the Toolcraft runtime clock/state path. Use custom timeline UI only for explicit `custom-reference-timeline` transfers with browser-backed reference timeline coverage.
|
|
187
|
+
Use `core/timeline-animation.md` for animation intent, playback/keyframe timeline choice, forward seamless loop rules, duration mapping, keyframe evaluation, viewport interaction performance, and video export timing.
|
|
320
188
|
|
|
321
189
|
## Panel Actions
|
|
322
190
|
|
|
323
|
-
Use `
|
|
324
|
-
|
|
325
|
-
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 add Import Settings or Export Settings to sticky footer `panelActions`; the runtime inserts them in the first visible headerless `Setup` controls block and imports/exports control values, canvas size, and timeline state.
|
|
326
|
-
|
|
327
|
-
Do not gate settings import/export by complexity thresholds, app size, or prompt wording. Use schema `settingsTransfer` only to customize exported JSON identity or file name.
|
|
328
|
-
|
|
329
|
-
When editable-output canvas sizing is enabled, the first `Setup` runtime section contains `Export Settings`, `Import Settings`, `Aspect ratio`, `Canvas width`, `Canvas height`, optional `Resolution scale`, and optional `Timeline` in that order. Do not split these into separate app-authored sections, rename the controls, rebuild the block by hand, or declare runtime Setup targets in product sections. App-authored controls targeting `runtime.settingsTransfer`, `canvas.aspectRatio`, `canvas.size.width`, `canvas.size.height`, `canvas.renderScale`, or `panels.timeline.extended` are invalid and never suppress the mandatory runtime controls.
|
|
330
|
-
|
|
331
|
-
If only `Export Settings` and `Import Settings` appear in that section, the schema is not using `editable-output` canvas sizing. For product-output apps, fix the canvas sizing decision instead of adding hand-built size fields. A reference, previous app, fixed-format baseline, or user-provided default size does not justify hiding size controls; keep those dimensions as editable `canvas.size` defaults.
|
|
332
|
-
|
|
333
|
-
Manual `Canvas width` or `Canvas height` edits are exact output-size edits. They keep the other dimension unchanged, switch `Aspect ratio` to `Custom`, and update the custom ratio inputs to the reduced current ratio. Do not recreate the old behavior where typing one size field stays locked to the previous aspect preset.
|
|
334
|
-
|
|
335
|
-
Enable `canvas.renderScale: true` for non-vector raster previews such as Canvas 2D, WebGL, or WebGPU output. Runtime adds a `Resolution scale` slider after canvas sizing; it defaults to `2` and lets users trade preview quality/performance without changing output size. Adding or enabling this slider requires targeted browser evidence that the canvas stays responsive while dragging sliders or other high-frequency controls at the selected scale. A full browser performance checkpoint is required for the first working product version and explicit performance complaints; use the agent-controlled browser first and `pnpm verify:perf` only as fallback. Performance fixes must preserve the selected scale and keep canvas preview responsive. Diagnose the actual bottleneck before lowering quality; do not silently downsample, stretch a lower-resolution backing canvas, blur output, or clamp `canvas.renderScale` below the user's chosen value. Do not enable it for DOM/SVG/vector-native previews.
|
|
336
|
-
|
|
337
|
-
When `panels.timeline` is enabled, runtime adds a `Timeline` switch as the last Setup control. It is a runtime presentation preference only: off shows compact Play-only transport, on shows the extended TimelinePanel with scrubber, duration, loop, and keyframe UI. It does not change playback, keyframes, export, product values, settings transfer, or Reset controls. `persistence.include: ["panels"]` may restore it. If `panels.timeline` is omitted, the Timeline switch must not be shown.
|
|
338
|
-
|
|
339
|
-
Reset belongs to the controls panel header reset button. Do not add a footer action with `label`, `value`, or `command` containing reset; acceptance treats that as a duplicate Reset.
|
|
340
|
-
|
|
341
|
-
Still-output product apps include one primary `Export PNG` action.
|
|
342
|
-
|
|
343
|
-
Animated product apps include `Export Video` as the primary action and `Export PNG` as the secondary action.
|
|
344
|
-
|
|
345
|
-
Export-labeled footer actions use `icon: "upload-simple"`, matching the runtime `Export Settings` button. Do not use `download`, `download-simple`, or `export` icons for `Export PNG` or `Export Video`.
|
|
346
|
-
|
|
347
|
-
Every product app with `Export PNG` includes a separate `Image Export` section. That section must contain:
|
|
348
|
-
|
|
349
|
-
- `export.image.format` as a `select`, with default value `png` and baseline options `png` and `jpg`;
|
|
350
|
-
- `export.image.resolution` as a `select`, with default value `4k` and baseline options `2k`, `4k`, and `8k`.
|
|
351
|
-
|
|
352
|
-
Place `Image Export` directly above sticky footer export buttons for still-output apps. For animated apps with both PNG and video export, place `Image Export` immediately before `Video Export`. `Format` and `Resolution` are one compact workflow pair: render them in a two-column inline row by default. Do not use `segmented` for this pair; it must visually match the Video Export dropdown structure.
|
|
353
|
-
|
|
354
|
-
Animated product apps with `Export Video` must enable the top Toolcraft timeline and include a separate `Video Export` section. That section must contain:
|
|
355
|
-
|
|
356
|
-
- `export.video.format` as a `select`, with default value `mp4` and baseline options `mp4` and `webm`;
|
|
357
|
-
- `export.video.resolution` as a `select`, with default value `current` and options such as `current` and `4k`.
|
|
358
|
-
|
|
359
|
-
Place `Video Export` as the final authored controls section directly above sticky footer export buttons. `Format` and `Resolution` are one compact workflow pair: render them in a two-column inline row by default. Use stacked rows only when a label or selected value would clip, truncate, or lose internal padding, and record that fallback reason in the spec or worklog. Do not use `segmented` for this pair unless the product has a deliberately tiny fixed output menu and browser tests prove every cell keeps padding.
|
|
360
|
-
|
|
361
|
-
Do not put video export format/resolution controls inside effect, renderer, animation, or output-background sections. `MOV` and `ProRes` are not baseline browser outputs; use them only with an explicit encoder/transcoder and dedicated acceptance plus performance coverage. Video exporters use `getToolcraftVideoExportSize`; do not hand-roll `4096` long-edge sizing for video. The `current` video option uses the current canvas/output size with even encoder-safe rounding. The `4k` video option fits inside 3840x2160, preserves aspect ratio, and returns even encoder-safe dimensions. Recorder/encoder errors must reject the export Promise instead of producing a corrupt blob.
|
|
362
|
-
|
|
363
|
-
Add `Copy PNG` only when clipboard output is part of the product. Copy never replaces export. If two footer actions are needed, secondary/outline goes left and primary goes right. Footer actions must be one compact horizontal group, not stacked full-width rows. If an odd number of actions leaves one action alone in the final row, that final action spans the full row.
|
|
364
|
-
|
|
365
|
-
Async footer actions return the real Promise from `ToolcraftApp onPanelAction`. Export, download, copy, generate, and apply must not run as fire-and-forget work; the runtime uses the returned Promise to show the sticky footer top accent indicator only while the operation is pending. Use `reportProgress(0..1)` from `onPanelAction` for determinate progress. Video export reports frame-based render/encode progress, and PNG export reports phase progress when render/blob/handoff are asynchronous.
|
|
366
|
-
|
|
367
|
-
Do not place product action buttons on the canvas or in the renderer.
|
|
191
|
+
Use `core/setup-export.md` for mandatory runtime Setup, background, Image Export, Video Export, sticky product actions, export icons, and async progress. Use `core/control-selection.md` for choosing `actions` versus sticky `panelActions`.
|
|
368
192
|
|
|
369
193
|
## Canvas Handles
|
|
370
194
|
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Control Selection
|
|
2
|
+
|
|
3
|
+
Read this module before adding, replacing, grouping, or custom-rendering controls.
|
|
4
|
+
|
|
5
|
+
## Built-In First
|
|
6
|
+
|
|
7
|
+
- Choose controls by product value model before UI appearance.
|
|
8
|
+
- Use built-in Toolcraft controls before custom controls.
|
|
9
|
+
- If multiple built-ins can work, choose the closest one and record the reason.
|
|
10
|
+
- If a built-in owner is discovered after a custom workaround, replace the workaround with the built-in.
|
|
11
|
+
- Custom controls are allowed only after documenting checked built-ins and why the closest one is insufficient.
|
|
12
|
+
|
|
13
|
+
## Control Selection Inventory
|
|
14
|
+
|
|
15
|
+
Before writing schema controls, map every user-visible product setting or action:
|
|
16
|
+
|
|
17
|
+
```txt
|
|
18
|
+
Product need:
|
|
19
|
+
Value model:
|
|
20
|
+
Candidate built-ins checked:
|
|
21
|
+
Best built-in:
|
|
22
|
+
Why:
|
|
23
|
+
Rejected alternatives:
|
|
24
|
+
Target:
|
|
25
|
+
Renderer/export mapping:
|
|
26
|
+
Acceptance coverage:
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This inventory can be in implementation notes, `starterControlSectionInventory`, or `docs/toolcraft/agent-worklog.md`, but the decision must exist before custom UI is introduced.
|
|
30
|
+
|
|
31
|
+
## Exact Owners
|
|
32
|
+
|
|
33
|
+
- Use `gradient` for adjustable gradients, color transitions, gradient fills, stops, type, and angle. Do not replace it with two `color` controls.
|
|
34
|
+
- Use `fontPicker` for typography that includes font family, weight, size, text case, text color/opacity, letter spacing, or line height.
|
|
35
|
+
- Use `colorOpacity` when one product entity owns both color and opacity.
|
|
36
|
+
- Use `rangeSlider` or `rangeInput` for lower/upper bounds or from/to ranges.
|
|
37
|
+
- Use `curves` for editable tone, response, easing, remapping, opacity, depth, mask, or channel curves.
|
|
38
|
+
- Use `vector` only for stable manually-authored two-axis product parameters such as position, offset, direction, focus, anchor, light direction, white balance, color balance, chroma offset, or tone bias.
|
|
39
|
+
- Use `fileDrop` for source material uploads.
|
|
40
|
+
- Use `imagePicker` for choosing one visual option from a set.
|
|
41
|
+
- Use `palette` only for constrained design-token color choices with both family and shade.
|
|
42
|
+
- Use `actions` for local section commands that affect only the nearby entity.
|
|
43
|
+
- Use `collectionActions` for repeatable product entities whose actual item list can grow or shrink.
|
|
44
|
+
- Use `panelActions` for sticky final product actions such as export, copy, generate, apply, or download.
|
|
45
|
+
|
|
46
|
+
## Compound Controls Are Atomic
|
|
47
|
+
|
|
48
|
+
- `fontPicker` owns font family, weight, size, text case, text color/opacity, letter spacing, and line height.
|
|
49
|
+
- `gradient` owns gradient type, angle, draggable stop track, and Stops list.
|
|
50
|
+
- RGB `curves`, `channelMixer`, `palette`, and `collectionActions` are also compound controls.
|
|
51
|
+
- Do not split owned fields into neighboring schema controls.
|
|
52
|
+
- If a needed owned field is missing from a built-in, extend the kit instead of composing a parallel control.
|
|
53
|
+
|
|
54
|
+
## Collection Actions
|
|
55
|
+
|
|
56
|
+
- Use `collectionActions` when users edit the actual growable/shrinkable set: colors, glyphs, symbols, points, rules, variants, objects, style entries, or similar repeatable entities.
|
|
57
|
+
- Adding/removing items must update runtime state and product preview/export.
|
|
58
|
+
- Do not use a count slider plus hidden fixed item controls when the user needs to add or remove actual entities.
|
|
59
|
+
- The collection control shows the collection label on the left and remove/add icon buttons on the right.
|
|
60
|
+
- Homogeneous repeated items do not show visible per-item labels when the collection label already names the group.
|
|
61
|
+
- Plain color items may use equal 50% columns; color+opacity items stay stacked.
|
|
62
|
+
|
|
63
|
+
## Actions
|
|
64
|
+
|
|
65
|
+
- Use schema `actions` for local section commands such as randomize palette, normalize weights, sort glyphs, clear selection, duplicate item, or reset current stop.
|
|
66
|
+
- If there is one `actions` button, the control label and button label must not be identical. Keep the button as the command verb and make the label a concise context.
|
|
67
|
+
- If an `actions` control has a visible label, the label is above the buttons.
|
|
68
|
+
- Actions render in 50% cells: one button uses the left half, two buttons fill one row, and larger groups continue in two columns.
|
|
69
|
+
- Do not stretch an odd trailing action full-width or center it.
|
|
70
|
+
- Keep final product actions in `panelActions`, keep timeline transport in the top timeline, and keep global reset in the controls panel header.
|
|
71
|
+
|
|
72
|
+
## Vector Ownership
|
|
73
|
+
|
|
74
|
+
Use Vector only when the user is meant to manually author a stable two-axis product parameter.
|
|
75
|
+
|
|
76
|
+
Before adding Vector to an animated or interactive product, classify movement ownership:
|
|
77
|
+
|
|
78
|
+
- `direct-authored`: stable user-authored parameter such as light direction, focus, anchor, or object offset. This can be Vector.
|
|
79
|
+
- `timeline-driven`: movement comes from playback/keyframes. Use timeline, speed, duration, path, step, or amplitude controls instead.
|
|
80
|
+
- `keyboard/pointer-driven`: movement comes from user input on the canvas/app. Keep current position/direction in interaction state and expose only useful tuning controls.
|
|
81
|
+
- `simulation-owned`: movement comes from physics/procedural state. Keep current pose/velocity internal and expose high-level tuning controls.
|
|
82
|
+
|
|
83
|
+
Do not expose a pad for current animation state, keyboard movement, pointer movement, physics state, timeline phase, velocity, target pose, current pose, or simulated position/direction just because the internal value has `x` and `y`.
|
|
84
|
+
|
|
85
|
+
## Custom Control Gate
|
|
86
|
+
|
|
87
|
+
- Custom controls are for product interactions that built-ins cannot represent.
|
|
88
|
+
- Custom controls must use Toolcraft primitives, tokens, spacing, typography, and action affordances.
|
|
89
|
+
- Custom controls must expose the minimum UI needed to understand and operate the product value.
|
|
90
|
+
- Every visible custom-control element must have a job: choose, order, preview, delete, upload, edit, or show useful status.
|
|
91
|
+
- Remove file names, helper text, and captions that do not help distinguish items or explain state.
|
|
92
|
+
- Do not make tiny item-level action buttons below kit comfort sizes.
|
|
93
|
+
- Do not recreate built-in controls, panels, toolbar, timeline, layers, canvas shell, or runtime surfaces.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Controls Layout
|
|
2
|
+
|
|
3
|
+
Read this module before changing sections, labels, helper icons, inline rows, dividers, action layouts, or panel density.
|
|
4
|
+
|
|
5
|
+
## Sections
|
|
6
|
+
|
|
7
|
+
- Build controls-panel sections from product entities and workflow stages, not component types.
|
|
8
|
+
- Before writing controls, export `starterControlSectionInventory`. Each product section declares title, product entity or workflow stage, targets, and grouping reason.
|
|
9
|
+
- Keep sections discrete. Two to seven product controls is the normal size.
|
|
10
|
+
- Split sections that grow past seven controls or mix several meanings.
|
|
11
|
+
- Do not reuse the same section title for multiple sections.
|
|
12
|
+
- Bad titles: `Controls`, `Settings`, `Options`, `Sliders`, `Inputs`, `Buttons`, `Color`, `Colors`.
|
|
13
|
+
- Good titles name the edited thing: `Background`, `Object`, `Token Pattern`, `Motion`, `Tone Mapping`, `Export`.
|
|
14
|
+
- Every app-authored controls-panel body section has a short meaningful visible title.
|
|
15
|
+
- Runtime `Setup` is the first visible headerless controls block. Sticky footer export actions render without a visible heading.
|
|
16
|
+
|
|
17
|
+
## Dependency Cohesion
|
|
18
|
+
|
|
19
|
+
- A selector that controls mode, type, source, variant, or include state stays with the controls it gates when they share the same product entity.
|
|
20
|
+
- Use `visibleWhen` for inactive product branches so the panel shows only usable controls.
|
|
21
|
+
- 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.
|
|
22
|
+
- A section with no visible controls is hidden automatically.
|
|
23
|
+
- Do not use `disabled: true` or `disabledWhen` for generated product controls.
|
|
24
|
+
|
|
25
|
+
## Section Headers And Reset
|
|
26
|
+
|
|
27
|
+
- Every visible section title renders through the standard 36px collapsible header row.
|
|
28
|
+
- Do not hand-build section headers in generated apps.
|
|
29
|
+
- Section expand/collapse uses the standard runtime height/opacity animation.
|
|
30
|
+
- Collapsed/expanded state persists as per-app runtime UI preference.
|
|
31
|
+
- Collapsed/expanded state is not undo/redo state, settings import/export state, or Reset controls state.
|
|
32
|
+
- Ordinary section headers expose the runtime section reset action before the collapse button.
|
|
33
|
+
- Section reset dispatches `controls.resetTargets` and restores only that section's targets to schema `defaultValue`.
|
|
34
|
+
- Runtime `Setup` is not collapsible and has no reset action. Sticky footer export sections are not collapsible.
|
|
35
|
+
|
|
36
|
+
## Section Spacing
|
|
37
|
+
|
|
38
|
+
- Runtime `Setup` and ordinary body sections use 8px top spacing and 24px bottom spacing for control content.
|
|
39
|
+
- Sticky footer action sections keep their dedicated spacing.
|
|
40
|
+
- Do not add custom padding in generated apps to compensate for a local section issue. Fix the shared layout rule.
|
|
41
|
+
|
|
42
|
+
## Dividers
|
|
43
|
+
|
|
44
|
+
- Full-width dividers belong only to panel sections.
|
|
45
|
+
- Large built-in compound controls inside a section render content-width internal dividers only when their parent section contains more than one visible control item.
|
|
46
|
+
- Keep 18px between each rendered internal divider and compound-control content.
|
|
47
|
+
- If the compound control is the first item in that section, render only its bottom internal divider and remove top internal padding.
|
|
48
|
+
- If the compound control is the last item, render only its top internal divider and remove bottom internal padding.
|
|
49
|
+
- If a section contains exactly one control, simple or compound, render only the parent section dividers.
|
|
50
|
+
- Do not add full-width borders inside a compound control.
|
|
51
|
+
- Do not put dividers only around an internal subsection such as Gradient Stops.
|
|
52
|
+
- Small compound fields such as `colorOpacity` and `rangeInput` stay inline fields without section dividers.
|
|
53
|
+
|
|
54
|
+
## Labels And Help
|
|
55
|
+
|
|
56
|
+
- Keep labels short but semantically sufficient with the nearest visible section/group context.
|
|
57
|
+
- Put product-specific behavior help in schema `description`.
|
|
58
|
+
- Runtime shows the help icon only when `description` adds meaning beyond the label.
|
|
59
|
+
- Do not use descriptions that recap the label, such as `Adjusts Opacity`.
|
|
60
|
+
- Do not add helper icons to obvious homogeneous groups when the section title and label already explain the control.
|
|
61
|
+
- In toggle components, do not prefix labels with `Enable`; the switch already communicates on/off.
|
|
62
|
+
- When a section title supplies the context, remove repeated nouns from nearby labels. For example, in `Background`, the switch label is `Include`, not `Include background`.
|
|
63
|
+
|
|
64
|
+
## Inline Rows
|
|
65
|
+
|
|
66
|
+
- Inline rows are allowed only when the controls are related, short, and preserve internal padding.
|
|
67
|
+
- Every 50/50 inline row uses the same horizontal column gap as paired select controls.
|
|
68
|
+
- Controls in a 50/50 row each occupy half the available content width.
|
|
69
|
+
- If any label or value clips, truncates, or loses internal padding, stack the controls and record the fit reason.
|
|
70
|
+
- Toggle-plus-parameter rows are allowed when the toggle enables/includes the same entity and the parameter is short. Keep the toggle label visible and set the non-toggle parameter `label: false`.
|
|
71
|
+
- If the non-toggle parameter label is necessary, stack the controls instead.
|
|
72
|
+
- Sliders and range sliders are full-width and do not sit in inline rows.
|
|
73
|
+
- Segmented controls are full-width and do not sit beside Switch, Color, Select, or another control.
|
|
74
|
+
- Standalone selects are full-width with label above dropdown. Use two-column select rows only for related short pairs such as export `Format` and `Resolution`.
|
|
75
|
+
|
|
76
|
+
## Actions Layout
|
|
77
|
+
|
|
78
|
+
- If an `actions` control has a visible label, the label is above the buttons.
|
|
79
|
+
- One action button occupies the left 50% cell.
|
|
80
|
+
- Two action buttons fill one row.
|
|
81
|
+
- Larger groups continue in two columns.
|
|
82
|
+
- Odd trailing actions stay in the left 50% cell.
|
|
83
|
+
- Sticky footer `panelActions` use the sticky footer action layout, where a final odd action can span the full row.
|
|
84
|
+
|
|
85
|
+
## Colors In Rows
|
|
86
|
+
|
|
87
|
+
- First identify the semantic entity the color belongs to: background, object, connector, glow, tone mapping, brand, export, or named product object.
|
|
88
|
+
- Keep color inside the entity section when it configures the same entity as nearby controls.
|
|
89
|
+
- Use a standalone color section only when color is the whole semantic section.
|
|
90
|
+
- Standalone color section titles must describe product role. Never create a section titled `Color` or `Colors`.
|
|
91
|
+
- Omit per-item labels such as `Color 1`, `Color 2`, or `Color 3` when colors only add variety to one shared palette/color bank.
|
|
92
|
+
- Keep visible labels when each color edits a distinct user-facing entity or role.
|
|
93
|
+
- Apply label visibility to the whole semantic color group; do not mix labeled and unlabeled items inside one bank.
|
|
94
|
+
- Multiple related plain colors render at most two per row.
|
|
95
|
+
- An odd trailing plain `color` keeps the same half-width footprint instead of stretching to full width.
|
|
96
|
+
- If any color has opacity, keep it stacked instead of placing it in a two-column row.
|
|
97
|
+
- `colorOpacity` owns color plus opacity for one entity and must not be split into color plus opacity slider/input.
|
|
98
|
+
|
|
99
|
+
## Select And Segmented Fit
|
|
100
|
+
|
|
101
|
+
- Standalone `select` controls render stacked and full-width.
|
|
102
|
+
- Use compact two-column select layout only for related short pairs that tune one workflow or entity.
|
|
103
|
+
- Segmented controls are full-width compact choices with at most four options, no option label longer than nine characters, and no more than twenty-four total option-label characters.
|
|
104
|
+
- If segmented cells clip, collide, lose padding, or force labels into adjacent cells, shorten labels first. If compact labels still fail, use `select`.
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Media Upload
|
|
2
|
+
|
|
3
|
+
Read this module before changing image upload, file upload, source material import, media defaults, source images, sorting, or image transform actions.
|
|
4
|
+
|
|
5
|
+
## FileDrop Ownership
|
|
6
|
+
|
|
7
|
+
- Use `fileDrop` for source material uploads in the controls panel.
|
|
8
|
+
- Do not place upload UI on the canvas.
|
|
9
|
+
- Do not build custom file lists, custom upload buttons, or custom sorting when `fileDrop` can represent the source set.
|
|
10
|
+
- Use `assetKind: "image"` for image-only source uploads.
|
|
11
|
+
- Use `assetKind: "file"` for arbitrary uploaded files.
|
|
12
|
+
- Image mode accepts images only by default.
|
|
13
|
+
- File mode accepts any file by default unless `accept` narrows extensions or MIME types.
|
|
14
|
+
|
|
15
|
+
## Empty Source State
|
|
16
|
+
|
|
17
|
+
- When upload/import is part of the source-material flow, the empty product canvas stays neutral.
|
|
18
|
+
- Do not invent canvas placeholder artwork, CTA copy, helper text, fake sample output, decorative placeholder, or agent-made source preset before real content exists.
|
|
19
|
+
- A default procedural/reference source is allowed only when the prompt or reference explicitly defines it and the worklog records the evidence.
|
|
20
|
+
|
|
21
|
+
## Image Uploads
|
|
22
|
+
|
|
23
|
+
- In single-layer apps, the runtime shows uploaded image preview and clear button in the file control.
|
|
24
|
+
- Clearing removes the attached source from the renderer and canvas.
|
|
25
|
+
- With exactly one uploaded image, image transform actions are visible immediately.
|
|
26
|
+
- With multiple uploaded images, users select a thumbnail first; until then transform actions are hidden.
|
|
27
|
+
- Once selected, transform actions apply only to that selected image.
|
|
28
|
+
- The FileDrop panel preview is not product canvas rendering. It keeps a stable preview frame across rotate/flip actions and contains the transformed bitmap inside that frame.
|
|
29
|
+
- Horizontal or vertical uploads must not be cropped by the control preview.
|
|
30
|
+
|
|
31
|
+
## Image Transform Actions
|
|
32
|
+
|
|
33
|
+
- Runtime owns image transform actions directly below image uploaders.
|
|
34
|
+
- Actions render through the built-in `actions` control, not through a custom image action grid.
|
|
35
|
+
- Use one row of three compact action buttons:
|
|
36
|
+
- `90°` for rotate right;
|
|
37
|
+
- `Flip H`;
|
|
38
|
+
- `Flip V`.
|
|
39
|
+
- Keep a 6px vertical gap between uploader and action row.
|
|
40
|
+
- Product preview/export consumes `state.mediaAssets[].transform`.
|
|
41
|
+
- Do not keep separate product-only image transform state.
|
|
42
|
+
|
|
43
|
+
## Multiple Uploads And Sorting
|
|
44
|
+
|
|
45
|
+
- Use `multiple: true` when the app needs several uploaded images or files as one source set.
|
|
46
|
+
- Multiple image uploads render as a sortable four-column thumbnail grid.
|
|
47
|
+
- The add-more tile is last.
|
|
48
|
+
- Per-image removal stays inside the file control.
|
|
49
|
+
- Dragging thumbnails updates runtime media order.
|
|
50
|
+
- Product renderers and exports consume runtime media order instead of keeping a separate product-only order.
|
|
51
|
+
|
|
52
|
+
## File Uploads
|
|
53
|
+
|
|
54
|
+
- In file mode, uploaded files render as a sortable list with a paperclip icon, filename, remove button, and `--border/5` separators.
|
|
55
|
+
- Long filenames fade/truncate at the end instead of hard-clipping.
|
|
56
|
+
- The last item has no bottom separator.
|
|
57
|
+
- The add row is part of the file control and uses the same width and hover behavior as list rows.
|
|
58
|
+
- When an app contains both image and file uploaders, canvas drops route by asset kind:
|
|
59
|
+
- image files prefer visible image uploaders;
|
|
60
|
+
- non-image files prefer visible file uploaders;
|
|
61
|
+
- file uploaders may accept images only when no image uploader matches.
|
|
62
|
+
- Product renderers filter `state.mediaAssets` by `sourceTarget`.
|
|
63
|
+
|
|
64
|
+
## Canvas Source Images
|
|
65
|
+
|
|
66
|
+
- Uploaded background/source images inside product canvases use `editable-output`.
|
|
67
|
+
- Uploaded source images do not change `canvas.size`.
|
|
68
|
+
- Setup canvas controls remain visible.
|
|
69
|
+
- Draw source/background images as cover/crop inside current canvas bounds without letterbox or aspect distortion.
|
|
70
|
+
- Scale proportionally until the current canvas bounds are fully covered, then crop overflow at canvas bounds.
|
|
71
|
+
- Reserve `intrinsic-media` for true media-viewer/source-native products where imported media natural dimensions intentionally own `canvas.size`, and prove that with acceptance coverage.
|
|
72
|
+
|
|
73
|
+
## Default Assets
|
|
74
|
+
|
|
75
|
+
- Use `media.defaultAssets` when an app starts with predefined files, source images, masks, symbol sets, or background images.
|
|
76
|
+
- Each default asset sets `sourceTarget` to the matching `fileDrop` target.
|
|
77
|
+
- Runtime treats these as attached files: users see them in the uploader, can remove them, and Reset restores them.
|
|
78
|
+
- If removal, reorder, or transforms of predefined media should survive reload, add `"media"` to `persistence.include`.
|
|
79
|
+
- Do not mirror the file list into product `values`.
|
|
80
|
+
- Do not hard-code default source files inside `canvasContent` or the renderer.
|
|
81
|
+
|
|
82
|
+
## Layers
|
|
83
|
+
|
|
84
|
+
- In multi-layer apps, deletion and visibility belong to the Layers panel.
|
|
85
|
+
- `fileDrop` stays an upload target.
|