@pixerate/editor 0.259.0 → 0.260.0
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/dist/agent/index.cjs +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/index.cjs +61 -59
- package/dist/animation-editor/index.js +5 -3
- package/dist/brushes/index.cjs +52 -52
- package/dist/brushes/index.js +6 -6
- package/dist/{brushstrokeRender-JI4W6F2G.js → brushstrokeRender-25Q5BEY6.js} +17 -7
- package/dist/{brushstrokeRender-MQ6PSDM5.cjs → brushstrokeRender-N6UPZSQS.cjs} +31 -21
- package/dist/canvas/brushTypes.d.cts +5 -0
- package/dist/canvas/brushTypes.d.ts +5 -0
- package/dist/canvas/drawController.d.cts +15 -1
- package/dist/canvas/drawController.d.ts +15 -1
- package/dist/canvas/index.cjs +136 -102
- package/dist/canvas/index.js +35 -1
- package/dist/{chunk-3PPJRMIG.js → chunk-3O47TPGX.js} +197 -18
- package/dist/{chunk-5Q5MLXAD.cjs → chunk-3TQW5MPW.cjs} +23 -23
- package/dist/{chunk-JBBJE76O.cjs → chunk-3ZRNK3RO.cjs} +1138 -85
- package/dist/{chunk-YSGW7VV4.cjs → chunk-43NT242D.cjs} +1401 -228
- package/dist/{chunk-SMTUQWGY.js → chunk-5IW65VQ6.js} +1 -1
- package/dist/{chunk-YQ4PQTBB.js → chunk-6NZL24W4.js} +9 -1
- package/dist/{chunk-O3ZVZSNJ.cjs → chunk-7AUQ2UJ3.cjs} +137 -129
- package/dist/{chunk-4M4E3N6X.js → chunk-CQVTGBQI.js} +1 -1
- package/dist/{chunk-SSFMWJDK.js → chunk-D4TE5JNW.js} +1192 -19
- package/dist/{chunk-AORZ5M5C.js → chunk-EHALWBBD.js} +1 -1
- package/dist/{chunk-6WCQ35GI.cjs → chunk-NHA26O5X.cjs} +2 -2
- package/dist/{chunk-DPYAO5U6.cjs → chunk-PVJMTLPJ.cjs} +197 -18
- package/dist/{chunk-MQGQTKVW.cjs → chunk-PYTJBVW5.cjs} +29 -29
- package/dist/{chunk-IXQZHCOF.js → chunk-QAR2N7HZ.js} +1 -1
- package/dist/{chunk-5P4JEOIV.js → chunk-TMDDMJCR.js} +2 -2
- package/dist/{chunk-RSIKDWOP.cjs → chunk-TZOX7KWV.cjs} +15 -15
- package/dist/{chunk-IPUTIUGQ.cjs → chunk-UVZ7RQOE.cjs} +1 -1
- package/dist/{chunk-A7GJ6BXI.js → chunk-WJ4WQJCC.js} +1062 -9
- package/dist/{chunk-ICTPLVSR.js → chunk-X2EXYY4J.js} +1 -1
- package/dist/{chunk-WQCNC4DK.js → chunk-XC6DPRYI.js} +695 -4
- package/dist/{chunk-KBYB7OWB.cjs → chunk-YHDHFJUC.cjs} +776 -85
- package/dist/{chunk-P3PZ63M3.cjs → chunk-YLUIFXSL.cjs} +35 -35
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/image-editor/index.cjs +1385 -2484
- package/dist/image-editor/index.js +139 -1238
- package/dist/image-editor/selection-worker.cjs +3 -4
- package/dist/image-editor/selection-worker.js +1 -2
- package/dist/paint/index.cjs +3 -5
- package/dist/paint/index.js +40 -42
- package/dist/paint-editor/contract.d.cts +29 -0
- package/dist/paint-editor/contract.d.ts +29 -0
- package/dist/paint-editor/dab-stroke.d.cts +5 -0
- package/dist/paint-editor/dab-stroke.d.ts +5 -0
- package/dist/paint-editor/index.cjs +402 -258
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +197 -53
- package/dist/paint-editor/stamp-tip.d.cts +17 -0
- package/dist/paint-editor/stamp-tip.d.ts +17 -0
- package/dist/paint-editor/ui.d.cts +21 -1
- package/dist/paint-editor/ui.d.ts +21 -1
- package/dist/raster/index.cjs +2 -4
- package/dist/raster/index.js +6 -8
- package/dist/vector/brushstroke.d.cts +6 -0
- package/dist/vector/brushstroke.d.ts +6 -0
- package/dist/vector/controller.d.cts +11 -2
- package/dist/vector/controller.d.ts +11 -2
- package/dist/vector/index.cjs +990 -973
- package/dist/vector/index.js +28 -11
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -1
- package/skills/pixerate-canvas/SKILL.md +3 -1
- package/skills/pixerate-vector/SKILL.md +2 -2
- package/dist/chunk-2VJAVXLI.js +0 -192
- package/dist/chunk-62Z5WLRA.js +0 -700
- package/dist/chunk-BOHDJJ2O.cjs +0 -192
- package/dist/chunk-NKGB64CW.cjs +0 -700
- package/dist/chunk-SS53NNZO.cjs +0 -1066
- package/dist/chunk-ZNA3IQZF.js +0 -1066
package/dist/vector/index.js
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
traceField,
|
|
27
27
|
traceVectorImage,
|
|
28
28
|
vectorTraceContours
|
|
29
|
-
} from "../chunk-
|
|
29
|
+
} from "../chunk-CQVTGBQI.js";
|
|
30
30
|
import {
|
|
31
31
|
applyHomography,
|
|
32
32
|
homographyFromPoints,
|
|
@@ -53,7 +53,7 @@ import {
|
|
|
53
53
|
reverseMorphContour,
|
|
54
54
|
subpathToMorphContour,
|
|
55
55
|
turnMorphContour
|
|
56
|
-
} from "../chunk-
|
|
56
|
+
} from "../chunk-QAR2N7HZ.js";
|
|
57
57
|
import {
|
|
58
58
|
DEFAULT_VECTOR_FONT,
|
|
59
59
|
IDENTITY_MATRIX,
|
|
@@ -380,6 +380,7 @@ import {
|
|
|
380
380
|
vectorBrushstrokeBrushOf,
|
|
381
381
|
vectorBrushstrokeBrushes,
|
|
382
382
|
vectorBrushstrokeCharacterError,
|
|
383
|
+
vectorBrushstrokeDefaultColour,
|
|
383
384
|
vectorBrushstrokeImages,
|
|
384
385
|
vectorBrushstrokeReach,
|
|
385
386
|
vectorChildAppearanceShapes,
|
|
@@ -528,10 +529,10 @@ import {
|
|
|
528
529
|
withVectorStrokes,
|
|
529
530
|
withVectorTargetPaint,
|
|
530
531
|
zigzagPaths
|
|
531
|
-
} from "../chunk-
|
|
532
|
+
} from "../chunk-6NZL24W4.js";
|
|
532
533
|
import {
|
|
533
534
|
snapshotBrushLibrary
|
|
534
|
-
} from "../chunk-
|
|
535
|
+
} from "../chunk-5IW65VQ6.js";
|
|
535
536
|
import "../chunk-APX63ILU.js";
|
|
536
537
|
import {
|
|
537
538
|
createProvenance
|
|
@@ -558,6 +559,8 @@ import {
|
|
|
558
559
|
fitCubics,
|
|
559
560
|
parseSvgPath
|
|
560
561
|
} from "../chunk-PWBZH3FK.js";
|
|
562
|
+
import "../chunk-FJBQTZS4.js";
|
|
563
|
+
import "../chunk-3CI7FRMK.js";
|
|
561
564
|
import {
|
|
562
565
|
StickerError
|
|
563
566
|
} from "../chunk-SZTI6EER.js";
|
|
@@ -6823,7 +6826,9 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
6823
6826
|
committing = false;
|
|
6824
6827
|
revision = 0;
|
|
6825
6828
|
state;
|
|
6829
|
+
colorScheme;
|
|
6826
6830
|
constructor(options = {}) {
|
|
6831
|
+
this.colorScheme = options.colorScheme ?? "light";
|
|
6827
6832
|
this.brushes = options.brushLibrary ? snapshotBrushLibrary(options.brushLibrary, () => this.notify()) : null;
|
|
6828
6833
|
this.history = options.history ?? new HistoryManager();
|
|
6829
6834
|
this.doc = options.document ? loadedDocument(options.document) : { width: 800, height: 600, nodes: [] };
|
|
@@ -8182,7 +8187,8 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8182
8187
|
* Adds a brushstroke to the selected (or given) paths: a stroke layer that paints the path with
|
|
8183
8188
|
* brush `brushId` (a preset, or a saved brush of the brush library: `listBrushstrokeBrushes`), `size` document
|
|
8184
8189
|
* units across (default the brush's own), an optional `pressure` profile along the length, in
|
|
8185
|
-
* `color` (default the
|
|
8190
|
+
* `color` (default the brush's own default colour, unless `keepColour`; else the top stroke's
|
|
8191
|
+
* paint, else black) at `opacity`. At the top of the stroke
|
|
8186
8192
|
* stack or at `index`. A `seed` gives it the brush's character (jitter and the grain of `paper`,
|
|
8187
8193
|
* `null` for none); without one it renders plain. One undo step.
|
|
8188
8194
|
*/
|
|
@@ -8196,9 +8202,10 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8196
8202
|
if (characterError) return { ok: false, message: characterError };
|
|
8197
8203
|
if (options.color !== void 0 && !parseVectorColor(options.color)) return { ok: false, message: `"${options.color}" is not a colour.` };
|
|
8198
8204
|
if (options.opacity !== void 0 && !(options.opacity >= 0 && options.opacity <= 1)) return { ok: false, message: "opacity must be from 0 to 1." };
|
|
8205
|
+
const own = options.keepColour ? null : vectorBrushstrokeDefaultColour(clean.brushId, user, this.colorScheme);
|
|
8199
8206
|
return this.editStacks("stroke", options.ids, "Add Brushstroke", (stack, path) => {
|
|
8200
8207
|
const top = [...stack].reverse().find((l) => (l.kind ?? "paint") === "paint");
|
|
8201
|
-
const paint = options.color ?? (typeof top?.paint === "string" && top.paint !== "none" ? top.paint : typeof path.stroke === "string" && path.stroke !== "none" ? path.stroke : "#000000");
|
|
8208
|
+
const paint = options.color ?? own ?? (typeof top?.paint === "string" && top.paint !== "none" ? top.paint : typeof path.stroke === "string" && path.stroke !== "none" ? path.stroke : "#000000");
|
|
8202
8209
|
const layer = { kind: "brushstroke", paint, brush: clean, ...options.opacity !== void 0 && options.opacity < 1 ? { opacity: options.opacity } : {} };
|
|
8203
8210
|
const at = options.index === void 0 ? stack.length : Math.min(stack.length, Math.max(0, Math.round(options.index)));
|
|
8204
8211
|
return [...stack.slice(0, at), layer, ...stack.slice(at)];
|
|
@@ -8208,7 +8215,8 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8208
8215
|
* Changes brushstroke layer `index` (in the stroke stack, 0 is the bottom) of the selected (or
|
|
8209
8216
|
* given) paths: another brush, size, pressure profile (null removes it), colour or opacity, the
|
|
8210
8217
|
* character `seed` (null removes it: plain dabs) or the `paper` (replaced whole: `null` for no
|
|
8211
|
-
* grain, `{}` for the default paper).
|
|
8218
|
+
* grain, `{}` for the default paper). Another brush without a `color` takes that brush's default
|
|
8219
|
+
* colour, if it has one, unless `keepColour`. Fails, changing nothing, when that layer is not a
|
|
8212
8220
|
* brushstroke. With `merge`, consecutive edits fold into one undo step.
|
|
8213
8221
|
*/
|
|
8214
8222
|
setBrushstroke(index, patch, options = {}) {
|
|
@@ -8236,12 +8244,18 @@ var VectorEditorController = class _VectorEditorController {
|
|
|
8236
8244
|
if (patch.seed === null) delete brush.seed;
|
|
8237
8245
|
else if (patch.seed !== void 0) brush.seed = patch.seed;
|
|
8238
8246
|
if (patch.paper !== void 0) brush.paper = patch.paper;
|
|
8239
|
-
const
|
|
8247
|
+
const own = patch.brushId && patch.brushId !== layer.brush.brushId && !patch.keepColour ? vectorBrushstrokeDefaultColour(patch.brushId, user, this.colorScheme) : null;
|
|
8248
|
+
const colour = patch.color ?? own;
|
|
8249
|
+
const next = { ...layer, brush: sanitizeVectorBrushstroke(brush, user) ?? layer.brush, ...colour ? { paint: colour } : {}, ...patch.opacity !== void 0 ? { opacity: patch.opacity } : {} };
|
|
8240
8250
|
return stack.map((l, i) => i === index ? next : l);
|
|
8241
8251
|
},
|
|
8242
8252
|
merge
|
|
8243
8253
|
);
|
|
8244
8254
|
}
|
|
8255
|
+
/** Sets the colour scheme that picks the side of a brush's light / dark default colour. Existing strokes keep their colour. */
|
|
8256
|
+
setColorScheme(scheme) {
|
|
8257
|
+
this.colorScheme = scheme;
|
|
8258
|
+
}
|
|
8245
8259
|
/** Removes layer `index` of the fill or stroke stack of the selected (or given) paths. */
|
|
8246
8260
|
removePaintLayer(kind, index, options = {}) {
|
|
8247
8261
|
return this.editStacks(
|
|
@@ -15932,7 +15946,8 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15932
15946
|
brushId: { type: "string", description: 'Brush id from vector.listBrushes, e.g. "pencil-hb".' },
|
|
15933
15947
|
size: { type: "number", exclusiveMinimum: 0, maximum: 500, description: "Brush diameter in document units (default: the brush's own)." },
|
|
15934
15948
|
pressure: { type: "array", items: { type: "number", minimum: 0, maximum: 1 }, minItems: 1, maxItems: 64, description: "Pressure 0\u20131 along the length, spread evenly from start to end (default: full pressure)." },
|
|
15935
|
-
color: { type: "string", description: "CSS colour (default: the path's stroke colour, else black)." },
|
|
15949
|
+
color: { type: "string", description: "CSS colour (default: the brush's own default colour, such as the ballpoint's blue, unless keepColour; else the path's stroke colour, else black)." },
|
|
15950
|
+
keepColour: { type: "boolean", description: "Ignore the brush's default colour and use the path's stroke colour (default false)." },
|
|
15936
15951
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131 (default 1)." },
|
|
15937
15952
|
index: { type: "integer", minimum: 0, description: "Position in the stroke stack, 0 the bottom (default: on top)." },
|
|
15938
15953
|
seed: { ...BRUSH_SEED, description: "Character seed 0\u20132147483647: turns on the brush's jitter and paper grain; the same seed always renders the same stroke (default: none, plain dabs)." },
|
|
@@ -15954,7 +15969,7 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15954
15969
|
...params.seed !== void 0 ? { seed: params.seed } : {},
|
|
15955
15970
|
...params.paper !== void 0 ? { paper: params.paper } : {}
|
|
15956
15971
|
},
|
|
15957
|
-
{ ...params.ids ? { ids: params.ids } : {}, ...params.index !== void 0 ? { index: params.index } : {}, ...params.color ? { color: params.color } : {}, ...params.opacity !== void 0 ? { opacity: params.opacity } : {} }
|
|
15972
|
+
{ ...params.ids ? { ids: params.ids } : {}, ...params.index !== void 0 ? { index: params.index } : {}, ...params.color ? { color: params.color } : {}, ...params.keepColour ? { keepColour: true } : {}, ...params.opacity !== void 0 ? { opacity: params.opacity } : {} }
|
|
15958
15973
|
)
|
|
15959
15974
|
);
|
|
15960
15975
|
const paths = [];
|
|
@@ -15979,7 +15994,8 @@ function createVectorCommands(controller, options = {}) {
|
|
|
15979
15994
|
brushId: { type: "string", description: "Another brush from vector.listBrushes." },
|
|
15980
15995
|
size: { type: ["number", "null"], description: "Diameter in document units, or null for the brush's own." },
|
|
15981
15996
|
pressure: { type: ["array", "null"], items: { type: "number", minimum: 0, maximum: 1 }, description: "Pressure profile 0\u20131 from start to end, or null for full pressure." },
|
|
15982
|
-
color: { type: "string", description: "CSS colour." },
|
|
15997
|
+
color: { type: "string", description: "CSS colour (with another brushId and no color, the new brush's default colour, if it has one, unless keepColour)." },
|
|
15998
|
+
keepColour: { type: "boolean", description: "With another brushId: keep the layer's colour instead of taking the new brush's default colour (default false)." },
|
|
15983
15999
|
opacity: { type: "number", minimum: 0, maximum: 1, description: "Layer opacity 0\u20131." },
|
|
15984
16000
|
seed: { anyOf: [BRUSH_SEED, { type: "null" }], description: "Character seed 0\u20132147483647 (jitter and paper grain; a new seed gives a new take on the same stroke), or null for plain dabs." },
|
|
15985
16001
|
paper: { anyOf: [BRUSH_PAPER, { type: "null" }], description: "The paper the grain comes from { pattern, seed, scale, depth } (applies with a seed), null for no grain, or {} for the default sanded paper." }
|
|
@@ -18873,6 +18889,7 @@ export {
|
|
|
18873
18889
|
vectorBrushstrokeBrushOf,
|
|
18874
18890
|
vectorBrushstrokeBrushes,
|
|
18875
18891
|
vectorBrushstrokeCharacterError,
|
|
18892
|
+
vectorBrushstrokeDefaultColour,
|
|
18876
18893
|
vectorBrushstrokeImages,
|
|
18877
18894
|
vectorBrushstrokeReach,
|
|
18878
18895
|
vectorBuilderErasedEdges,
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@ built-in presets (read-only) and the user's brushes, shared by every editor that
|
|
|
21
21
|
| Behaviour | `surface` `dry`, `wet` (`wet` settings) or `thick` (`thick` impasto settings); paper `grain`; `exchange` (pick-up and mix; a `reservoir` makes a Mixer Brush); tool `strength`. |
|
|
22
22
|
| Light | Light the brush gives off (`amount`), plus suggested layer `spill` and `glow`. |
|
|
23
23
|
| Motion | Animation after painting (live effect paint, particle `waveSpeed`). |
|
|
24
|
-
| Colour | A `default` colour, a `palette` of up to 16, `own` (always its own colour). Each is a hex or `rgba()` colour, a light / dark pair `{ light, dark }`, a gradient or effect paint. A gradient default is always painted; a solid or light / dark default becomes the editor's colour when the brush is chosen (unless the user locked theirs), resolved for the colour scheme. |
|
|
24
|
+
| Colour | A `default` colour, a `palette` of up to 16, `own` (always its own colour). Each is a hex or `rgba()` colour, a light / dark pair `{ light, dark }`, a gradient or effect paint. A gradient default is always painted; a solid or light / dark default becomes the editor's colour when the brush is chosen (unless the user locked theirs), resolved for the colour scheme. Canvas strokes and vector brushstrokes take it too, when they are given no colour. |
|
|
25
25
|
|
|
26
26
|
How media map to facets: a **pencil** or **charcoal** is `dry` with high `grain` and tilt;
|
|
27
27
|
**ink** is a hard round tip with pressure to size (a pen thins with velocity); **watercolour**
|
|
@@ -99,6 +99,8 @@ you to. Withdraw stale ones with `reject_proposal`: when the user changes what a
|
|
|
99
99
|
one width), the airbrush is a soft spray. The grain and jitter are seeded per stroke, so a
|
|
100
100
|
stroke always looks the same, and neighbouring strokes share one sheet of paper. Pick the brush
|
|
101
101
|
for the look, then the colour; for a sketch, use one or two brushes rather than all of them.
|
|
102
|
+
A brush with a default colour (ballpoint blue, highlighter yellow, chalk) paints in it when
|
|
103
|
+
you pass no `color`; pass `color` to use another.
|
|
102
104
|
- **Annotate with gestures, not points.** To mark up work the way a designer marks up a print,
|
|
103
105
|
use the gesture commands (`canvas.circle`, `canvas.underline`, `canvas.arrow`,
|
|
104
106
|
`canvas.bracket`, `canvas.strike`, `canvas.cross`, `canvas.check`) with node ids
|
|
@@ -251,7 +253,7 @@ character: seeded jitter and the paper grain they catch) and, when a width was c
|
|
|
251
253
|
|
|
252
254
|
| Command | Use it to |
|
|
253
255
|
| --- | --- |
|
|
254
|
-
| `canvas.drawFreehand` | Draw a pen or highlighter stroke through `points` (`[x, y]` pairs in canvas units, in drawing order; one undo step). `tool` picks the defaults (`pen`: blue, width 3; `highlighter`: yellow, width 24, opacity 0.35); `color`, `width`, `opacity` override them (with a `brush`, `width` is the brush diameter and defaults to the preset's own size). Pass `brush` (a preset or saved brush id from `canvas.listBrushes`, or tip settings) to paint it with a dry brush, plus `pressure` / `tiltX` / `tiltY` profiles spread along its length (`[0.2, 1, 0.3]` swells in the middle). Add `paint` (only with `brush`) for gradient paint that changes colour along the stroke: `{ "type": "gradient", "stops": [...], "map": { "by": "distance", "length": 200 } }` (length in canvas units), or `by` `pressure`, `tilt`, `direction`, `across-tip`, `random`. Returns the node `id`, its `bounds` and the stored `brush` (with `paint` normalised: defaults filled in, colours lowercased). |
|
|
256
|
+
| `canvas.drawFreehand` | Draw a pen or highlighter stroke through `points` (`[x, y]` pairs in canvas units, in drawing order; one undo step). `tool` picks the defaults (`pen`: blue, width 3; `highlighter`: yellow, width 24, opacity 0.35); `color`, `width`, `opacity` override them (with a `brush` and no `color`, the brush's default colour if it has one; with a `brush`, `width` is the brush diameter and defaults to the preset's own size). Pass `brush` (a preset or saved brush id from `canvas.listBrushes`, or tip settings) to paint it with a dry brush, plus `pressure` / `tiltX` / `tiltY` profiles spread along its length (`[0.2, 1, 0.3]` swells in the middle). Add `paint` (only with `brush`) for gradient paint that changes colour along the stroke: `{ "type": "gradient", "stops": [...], "map": { "by": "distance", "length": 200 } }` (length in canvas units), or `by` `pressure`, `tilt`, `direction`, `across-tip`, `random`. Returns the node `id`, its `bounds` and the stored `brush` (with `paint` normalised: defaults filled in, colours lowercased). |
|
|
255
257
|
| `canvas.listBrushes` | Read-only: the brushes `canvas.drawFreehand` and the gestures accept as `brush`: the dry presets, then saved brushes from the brush library the canvas can paint (`id`, `name`, `category`, the brush's own `size`, which a stroke uses unless you pass `width`, and `builtin`). Call it before the first brushed stroke instead of guessing ids. |
|
|
256
258
|
|
|
257
259
|
Gestures draw one hand-drawn stroke node each (one undo step) through the same path as
|
|
@@ -374,8 +374,8 @@ contents whole while you work, without losing the mask.
|
|
|
374
374
|
| Command | Use it to |
|
|
375
375
|
| --- | --- |
|
|
376
376
|
| `vector.listBrushes` | List the brushes a brushstroke can use: the dry presets (pencils, pastels, charcoal, crayon, chalk, markers, inks, ballpoint, gel pen, fineliner), then saved brushes from the brush library the vector profile admits, with their sizes and `builtin`. Brushes it refuses (wet, thick, particles, stickers, tools) are refused by `vector.addBrushstroke` with the reason. A saved brush is kept in the layer, so the document renders without the library. |
|
|
377
|
-
| `vector.addBrushstroke` | Paint paths with a brush along their outline (`brushId`, `size`, `pressure` profile such as [0.2, 1, 0.2] for a taper, `color`): sketchy, hand-drawn or inked lines that stay editable. Pass a `seed` (any integer) so the brush gets its character, the seeded jitter and paper grain that make pencil, pastel and charcoal look real; `paper` picks the grain (`{ pattern, seed, scale, depth }`) or `null` turns it off. Returns the stroke stacks. |
|
|
378
|
-
| `vector.setBrushstroke` | Change brushstroke layer `index` of path `id`: brush, size, pressure, colour, opacity, `seed` (a new seed is a new take on the same stroke; null: plain dabs) and `paper` (replaced whole; null: no grain; {}: the default sanded paper). Remove it with `vector.removeStroke`. |
|
|
377
|
+
| `vector.addBrushstroke` | Paint paths with a brush along their outline (`brushId`, `size`, `pressure` profile such as [0.2, 1, 0.2] for a taper, `color`, default the brush's default colour (ballpoint blue, chalk), else the path's stroke; `keepColour` keeps the path's colour): sketchy, hand-drawn or inked lines that stay editable. Pass a `seed` (any integer) so the brush gets its character, the seeded jitter and paper grain that make pencil, pastel and charcoal look real; `paper` picks the grain (`{ pattern, seed, scale, depth }`) or `null` turns it off. Returns the stroke stacks. |
|
|
378
|
+
| `vector.setBrushstroke` | Change brushstroke layer `index` of path `id`: brush (another brush without `color` takes its default colour, unless `keepColour`), size, pressure, colour, opacity, `seed` (a new seed is a new take on the same stroke; null: plain dabs) and `paper` (replaced whole; null: no grain; {}: the default sanded paper). Remove it with `vector.removeStroke`. |
|
|
379
379
|
|
|
380
380
|
Give brushstrokes a `seed` unless you want flat, even dabs: without one a charcoal or pastel line looks like a felt pen. Use different seeds on neighbouring strokes so they do not repeat each other, and `paper: null` for clean ink or marker lines that should not catch grain. The grain is laid in each path's own space, so it moves with the path.
|
|
381
381
|
|
package/dist/chunk-2VJAVXLI.js
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
LAYER_EFFECT_KINDS,
|
|
3
|
-
builtinPattern,
|
|
4
|
-
builtinPatternIds,
|
|
5
|
-
defaultEffectGradient,
|
|
6
|
-
hasActiveEffects,
|
|
7
|
-
layerEffectLabel
|
|
8
|
-
} from "./chunk-3PPJRMIG.js";
|
|
9
|
-
import {
|
|
10
|
-
BLEND_MODES
|
|
11
|
-
} from "./chunk-IRSTHLQQ.js";
|
|
12
|
-
|
|
13
|
-
// src/raster/effects/ui.ts
|
|
14
|
-
function layerEffectsPanel(layer) {
|
|
15
|
-
const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
|
|
16
|
-
if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
|
|
17
|
-
if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
|
|
18
|
-
const fx = layer.effects;
|
|
19
|
-
const readOnly = Boolean(layer.locks?.all);
|
|
20
|
-
return {
|
|
21
|
-
available: true,
|
|
22
|
-
readOnly,
|
|
23
|
-
reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
|
|
24
|
-
enabled: fx?.enabled ?? true,
|
|
25
|
-
scale: fx?.scale ?? 1,
|
|
26
|
-
rows: (fx?.items ?? []).map((e) => ({ id: e.id, kind: e.kind, label: layerEffectLabel(e.kind), enabled: e.enabled }))
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
function layerEffectsBadge(layer) {
|
|
30
|
-
if (!layer.effects?.items.length) return null;
|
|
31
|
-
return hasActiveEffects(layer.effects) ? "on" : "off";
|
|
32
|
-
}
|
|
33
|
-
var LAYER_EFFECT_MENU = LAYER_EFFECT_KINDS.map((kind) => ({ kind, label: layerEffectLabel(kind) }));
|
|
34
|
-
var BLENDS = BLEND_MODES.filter((m) => m.id !== "pigment").map((m) => ({ value: m.id, label: m.label }));
|
|
35
|
-
var opt = (...pairs) => pairs.map(([value, label]) => ({ value, label }));
|
|
36
|
-
function patternOptions(patterns) {
|
|
37
|
-
return [...patterns.map((p) => ({ value: p.id, label: p.name || p.id })), ...builtinPatternIds().map((id) => ({ value: id, label: builtinPattern(id).name }))];
|
|
38
|
-
}
|
|
39
|
-
function getPath(o, path) {
|
|
40
|
-
let v = o;
|
|
41
|
-
for (const p of path.split(".")) {
|
|
42
|
-
if (v === null || v === void 0) return void 0;
|
|
43
|
-
if (Array.isArray(v)) v = p === "last" ? v[v.length - 1] : v[Number(p)];
|
|
44
|
-
else v = v[p];
|
|
45
|
-
}
|
|
46
|
-
return v;
|
|
47
|
-
}
|
|
48
|
-
function setPath(o, parts, value) {
|
|
49
|
-
if (!parts.length) return value;
|
|
50
|
-
const [p, ...rest] = parts;
|
|
51
|
-
if (Array.isArray(o)) {
|
|
52
|
-
const i = p === "last" ? o.length - 1 : Number(p);
|
|
53
|
-
const out = [...o];
|
|
54
|
-
out[i] = setPath(o[i], rest, value);
|
|
55
|
-
return out;
|
|
56
|
-
}
|
|
57
|
-
const r = o ?? {};
|
|
58
|
-
return { ...r, [p]: setPath(r[p], rest, value) };
|
|
59
|
-
}
|
|
60
|
-
function fillControls(f, allowPattern, patterns) {
|
|
61
|
-
const types = allowPattern ? opt(["color", "Color"], ["gradient", "Gradient"], ["pattern", "Pattern"]) : opt(["color", "Color"], ["gradient", "Gradient"]);
|
|
62
|
-
const out = [{ key: "fill.type", label: "Fill", type: "select", value: f.type, options: types }];
|
|
63
|
-
if (f.type === "color") out.push({ key: "fill.color", label: "Color", type: "color", value: f.color });
|
|
64
|
-
else if (f.type === "gradient") out.push(...gradientControls("fill.gradient", f.gradient));
|
|
65
|
-
else {
|
|
66
|
-
out.push(
|
|
67
|
-
{ key: "fill.patternId", label: "Pattern", type: "select", value: f.patternId, options: patternOptions(patterns) },
|
|
68
|
-
{ key: "fill.scale", label: "Scale", type: "range", min: 0.01, max: 10, step: 0.01, value: f.scale, percent: true, unit: "%" }
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
return out;
|
|
72
|
-
}
|
|
73
|
-
function gradientControls(prefix, g) {
|
|
74
|
-
return [
|
|
75
|
-
{ key: `${prefix}.stops.0.color`, label: "Start colour", type: "color", value: g.stops[0]?.color ?? "#000000" },
|
|
76
|
-
{ key: `${prefix}.stops.last.color`, label: "End colour", type: "color", value: g.stops[g.stops.length - 1]?.color ?? "#ffffff" },
|
|
77
|
-
{ key: `${prefix}.style`, label: "Style", type: "select", value: g.style, options: opt(["linear", "Linear"], ["radial", "Radial"], ["angle", "Angle"], ["reflected", "Reflected"], ["diamond", "Diamond"]) },
|
|
78
|
-
{ key: `${prefix}.angle`, label: "Angle", type: "range", min: -180, max: 180, step: 1, value: g.angle, unit: "\xB0" },
|
|
79
|
-
{ key: `${prefix}.scale`, label: "Scale", type: "range", min: 0.1, max: 1.5, step: 0.01, value: g.scale, percent: true, unit: "%" },
|
|
80
|
-
{ key: `${prefix}.reverse`, label: "Reverse", type: "checkbox", value: g.reverse },
|
|
81
|
-
{ key: `${prefix}.align`, label: "Align with layer", type: "checkbox", value: g.align }
|
|
82
|
-
];
|
|
83
|
-
}
|
|
84
|
-
var px = (key, label, value, max = 250) => ({ key, label, type: "range", min: 0, max, step: 1, value, unit: "px" });
|
|
85
|
-
var pct = (key, label, value, min = 0, max = 1) => ({ key, label, type: "range", min, max, step: 0.01, value, percent: true, unit: "%" });
|
|
86
|
-
var deg = (key, label, value, min = -180, max = 180) => ({ key, label, type: "range", min, max, step: 1, value, unit: "\xB0" });
|
|
87
|
-
function layerEffectControls(e, patterns = []) {
|
|
88
|
-
const blended = e.kind === "bevel-emboss" ? [] : [
|
|
89
|
-
{ key: "blend", label: "Blend mode", type: "select", value: e.blend, options: BLENDS },
|
|
90
|
-
pct("opacity", "Opacity", e.opacity)
|
|
91
|
-
];
|
|
92
|
-
switch (e.kind) {
|
|
93
|
-
case "drop-shadow":
|
|
94
|
-
case "inner-shadow":
|
|
95
|
-
return [
|
|
96
|
-
...blended,
|
|
97
|
-
{ key: "color", label: "Color", type: "color", value: e.color },
|
|
98
|
-
{ key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
|
|
99
|
-
deg("angle", "Angle", e.angle),
|
|
100
|
-
px("distance", "Distance", e.distance, 500),
|
|
101
|
-
e.kind === "drop-shadow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
|
|
102
|
-
px("size", "Size", e.size),
|
|
103
|
-
pct("noise", "Noise", e.noise),
|
|
104
|
-
...e.kind === "drop-shadow" ? [{ key: "knocksOut", label: "Layer knocks out shadow", type: "checkbox", value: e.knocksOut }] : []
|
|
105
|
-
];
|
|
106
|
-
case "outer-glow":
|
|
107
|
-
case "inner-glow":
|
|
108
|
-
return [
|
|
109
|
-
...blended,
|
|
110
|
-
...fillControls(e.fill, false, patterns),
|
|
111
|
-
{ key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["softer", "Softer"], ["precise", "Precise"]) },
|
|
112
|
-
...e.kind === "inner-glow" ? [{ key: "source", label: "Source", type: "select", value: e.source, options: opt(["edge", "Edge"], ["center", "Center"]) }] : [],
|
|
113
|
-
e.kind === "outer-glow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
|
|
114
|
-
px("size", "Size", e.size),
|
|
115
|
-
pct("range", "Range", e.range, 0.01, 1),
|
|
116
|
-
pct("noise", "Noise", e.noise)
|
|
117
|
-
];
|
|
118
|
-
case "bevel-emboss":
|
|
119
|
-
return [
|
|
120
|
-
{ key: "style", label: "Style", type: "select", value: e.style, options: opt(["inner-bevel", "Inner Bevel"], ["outer-bevel", "Outer Bevel"], ["emboss", "Emboss"], ["pillow-emboss", "Pillow Emboss"], ["stroke-emboss", "Stroke Emboss"]) },
|
|
121
|
-
{ key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["smooth", "Smooth"], ["chisel-hard", "Chisel Hard"], ["chisel-soft", "Chisel Soft"]) },
|
|
122
|
-
pct("depth", "Depth", e.depth, 0, 10),
|
|
123
|
-
{ key: "direction", label: "Direction", type: "select", value: e.direction, options: opt(["up", "Up"], ["down", "Down"]) },
|
|
124
|
-
px("size", "Size", e.size),
|
|
125
|
-
px("soften", "Soften", e.soften, 16),
|
|
126
|
-
{ key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
|
|
127
|
-
deg("angle", "Angle", e.angle),
|
|
128
|
-
deg("altitude", "Altitude", e.altitude, 0, 90),
|
|
129
|
-
{ key: "highlightColor", label: "Highlight", type: "color", value: e.highlightColor },
|
|
130
|
-
{ key: "highlightBlend", label: "Highlight mode", type: "select", value: e.highlightBlend, options: BLENDS },
|
|
131
|
-
pct("highlightOpacity", "Highlight opacity", e.highlightOpacity),
|
|
132
|
-
{ key: "shadowColor", label: "Shadow", type: "color", value: e.shadowColor },
|
|
133
|
-
{ key: "shadowBlend", label: "Shadow mode", type: "select", value: e.shadowBlend, options: BLENDS },
|
|
134
|
-
pct("shadowOpacity", "Shadow opacity", e.shadowOpacity)
|
|
135
|
-
];
|
|
136
|
-
case "satin":
|
|
137
|
-
return [
|
|
138
|
-
...blended,
|
|
139
|
-
{ key: "color", label: "Color", type: "color", value: e.color },
|
|
140
|
-
deg("angle", "Angle", e.angle),
|
|
141
|
-
px("distance", "Distance", e.distance),
|
|
142
|
-
px("size", "Size", e.size),
|
|
143
|
-
{ key: "invert", label: "Invert", type: "checkbox", value: e.invert }
|
|
144
|
-
];
|
|
145
|
-
case "color-overlay":
|
|
146
|
-
return [...blended, { key: "color", label: "Color", type: "color", value: e.color }];
|
|
147
|
-
case "gradient-overlay":
|
|
148
|
-
return [...blended, ...gradientControls("gradient", e.gradient)];
|
|
149
|
-
case "pattern-overlay":
|
|
150
|
-
return [
|
|
151
|
-
...blended,
|
|
152
|
-
{ key: "patternId", label: "Pattern", type: "select", value: e.patternId, options: patternOptions(patterns) },
|
|
153
|
-
pct("scale", "Scale", e.scale, 0.01, 10),
|
|
154
|
-
deg("angle", "Angle", e.angle ?? 0),
|
|
155
|
-
{ key: "link", label: "Link with layer", type: "checkbox", value: e.link ?? true }
|
|
156
|
-
];
|
|
157
|
-
case "stroke":
|
|
158
|
-
return [
|
|
159
|
-
...blended,
|
|
160
|
-
px("size", "Size", e.size),
|
|
161
|
-
{ key: "position", label: "Position", type: "select", value: e.position, options: opt(["outside", "Outside"], ["inside", "Inside"], ["center", "Center"]) },
|
|
162
|
-
...fillControls(e.fill, true, patterns)
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
function fillOfType(current, type, patterns) {
|
|
167
|
-
if (type === "gradient") return { type: "gradient", gradient: defaultEffectGradient() };
|
|
168
|
-
if (type === "pattern") return { type: "pattern", patternId: patterns[0]?.id ?? "checker", scale: 1 };
|
|
169
|
-
return { type: "color", color: current.type === "color" ? current.color : "#000000" };
|
|
170
|
-
}
|
|
171
|
-
function effectControlChange(effect, key, value, patterns = []) {
|
|
172
|
-
const [top, ...rest] = key.split(".");
|
|
173
|
-
if (top === "fill" && rest[0] === "type") return { fill: fillOfType(effect.fill, String(value), patterns) };
|
|
174
|
-
if (top === "patternId" && !rest.length) {
|
|
175
|
-
const name = patternOptions(patterns).find((o) => o.value === value)?.label;
|
|
176
|
-
return name ? { patternId: value, name } : { patternId: value };
|
|
177
|
-
}
|
|
178
|
-
if (!rest.length) return { [top]: value };
|
|
179
|
-
if (top === "fill" && rest[0] === "patternId") {
|
|
180
|
-
const name = patternOptions(patterns).find((o) => o.value === value)?.label;
|
|
181
|
-
return { fill: { ...effect.fill, patternId: value, ...name ? { name } : {} } };
|
|
182
|
-
}
|
|
183
|
-
return { [top]: setPath(getPath(effect, top), rest, value) };
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
export {
|
|
187
|
-
layerEffectsPanel,
|
|
188
|
-
layerEffectsBadge,
|
|
189
|
-
LAYER_EFFECT_MENU,
|
|
190
|
-
layerEffectControls,
|
|
191
|
-
effectControlChange
|
|
192
|
-
};
|