@pixerate/editor 0.266.2 → 0.268.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/controller.d.cts +8 -0
- package/dist/animation-editor/controller.d.ts +8 -0
- package/dist/animation-editor/effect-tools.d.cts +1 -1
- package/dist/animation-editor/effect-tools.d.ts +1 -1
- package/dist/animation-editor/index.cjs +175 -108
- package/dist/animation-editor/index.js +94 -27
- package/dist/brushes/index.cjs +201 -75
- package/dist/brushes/index.d.cts +4 -3
- package/dist/brushes/index.d.ts +4 -3
- package/dist/brushes/index.js +138 -12
- package/dist/brushes/library.d.cts +27 -1
- package/dist/brushes/library.d.ts +27 -1
- package/dist/brushes/profiles.d.cts +10 -1
- package/dist/brushes/profiles.d.ts +10 -1
- package/dist/brushes/schema.d.cts +4 -0
- package/dist/brushes/schema.d.ts +4 -0
- package/dist/brushes/sources.d.cts +114 -0
- package/dist/brushes/sources.d.ts +114 -0
- package/dist/brushes/types.d.cts +37 -5
- package/dist/brushes/types.d.ts +37 -5
- package/dist/brushes/ui.d.cts +40 -4
- package/dist/brushes/ui.d.ts +40 -4
- package/dist/{brushstrokeRender-KD453OBX.js → brushstrokeRender-A727TTNQ.js} +7 -7
- package/dist/{brushstrokeRender-FSUWXUZY.cjs → brushstrokeRender-WR2N5HHY.cjs} +23 -23
- package/dist/canvas/brushTypes.d.cts +12 -0
- package/dist/canvas/brushTypes.d.ts +12 -0
- package/dist/canvas/brushstroke.d.cts +1 -1
- package/dist/canvas/brushstroke.d.ts +1 -1
- package/dist/canvas/drawController.d.cts +19 -4
- package/dist/canvas/drawController.d.ts +19 -4
- package/dist/canvas/index.cjs +144 -105
- package/dist/canvas/index.js +46 -7
- package/dist/{chunk-TOID45I2.cjs → chunk-2WOGXEDX.cjs} +1 -1
- package/dist/{chunk-XORJ7UZO.cjs → chunk-3VHH6V67.cjs} +13 -12
- package/dist/{chunk-3C33YTNN.js → chunk-3XDSNIGF.js} +73 -6
- package/dist/chunk-62MFUHSI.cjs +802 -0
- package/dist/{chunk-R44Y3EFS.js → chunk-74ODPZLX.js} +17 -345
- package/dist/{chunk-GCVFEPJG.js → chunk-ACTHSQOI.js} +182 -0
- package/dist/chunk-ADMRNWR7.js +340 -0
- package/dist/{chunk-MVUQSK5J.cjs → chunk-B3G7BKUV.cjs} +111 -439
- package/dist/{chunk-DXYHQ2VN.js → chunk-BAZMCFVL.js} +1 -1
- package/dist/{chunk-VRK322ZC.cjs → chunk-BPJSI4NT.cjs} +2 -2
- package/dist/{chunk-RFJZGTHA.cjs → chunk-EU2ZZA6L.cjs} +400 -69
- package/dist/{chunk-XC6DPRYI.js → chunk-GSTSZPSR.js} +154 -949
- package/dist/{chunk-EZOJBP4D.js → chunk-HFY5LG5J.js} +1 -1
- package/dist/chunk-HVO6XCI4.js +802 -0
- package/dist/{chunk-YHDHFJUC.cjs → chunk-J5VQYK7T.cjs} +217 -1012
- package/dist/{chunk-XRXFVRGY.cjs → chunk-JBB3GDBB.cjs} +2483 -208
- package/dist/{chunk-ACFSFUQH.js → chunk-JL6YH5WD.js} +4 -0
- package/dist/{chunk-CIJBSUM5.js → chunk-KZI3YWKW.js} +353 -22
- package/dist/{chunk-4ODRXQRW.js → chunk-LETF75CA.js} +1 -1
- package/dist/{chunk-FQPUF2W2.cjs → chunk-NIBFKXMD.cjs} +217 -35
- package/dist/{chunk-AQZQWXEU.cjs → chunk-NPWWSCWT.cjs} +35 -35
- package/dist/{chunk-DOZ6F2K2.js → chunk-NSETJI74.js} +3 -2
- package/dist/{chunk-PE6YJMQT.cjs → chunk-PFHJS4HE.cjs} +20 -19
- package/dist/{chunk-7KNW3WXZ.cjs → chunk-QEVLRLUN.cjs} +63 -0
- package/dist/{chunk-LK4SXL3V.js → chunk-QNY7BDFP.js} +1 -1
- package/dist/{chunk-OTN6VB5S.cjs → chunk-RDFHWAHL.cjs} +5 -1
- package/dist/{chunk-PXDIAYB6.cjs → chunk-STLTOISW.cjs} +34 -214
- package/dist/{chunk-T2LDTEXK.js → chunk-UVTO3D4E.js} +2333 -58
- package/dist/{chunk-6JL2D5SG.js → chunk-VE6UKYQ2.js} +3 -2
- package/dist/{chunk-TXFWZ5ZJ.js → chunk-W6JDUXP3.js} +4 -184
- package/dist/{chunk-3SBLVGOM.cjs → chunk-YOVXQHA3.cjs} +23 -23
- package/dist/{chunk-WLUVZKVD.cjs → chunk-YXP6X3SY.cjs} +103 -36
- package/dist/chunk-YZWM6ZIP.cjs +340 -0
- package/dist/{chunk-472INMWH.js → chunk-ZA7L5YJB.js} +63 -0
- package/dist/commands/builtins.d.cts +12 -1
- package/dist/commands/builtins.d.ts +12 -1
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/image-editor/controller.d.cts +1 -1
- package/dist/image-editor/controller.d.ts +1 -1
- package/dist/image-editor/index.cjs +868 -864
- package/dist/image-editor/index.js +123 -119
- package/dist/paint/index.cjs +8 -6
- package/dist/paint/index.js +56 -54
- package/dist/paint-editor/brush-library-tools.d.cts +12 -2
- package/dist/paint-editor/brush-library-tools.d.ts +12 -2
- package/dist/paint-editor/brush-model.d.cts +29 -1
- package/dist/paint-editor/brush-model.d.ts +29 -1
- package/dist/paint-editor/brush-source-art.d.cts +32 -0
- package/dist/paint-editor/brush-source-art.d.ts +32 -0
- package/dist/paint-editor/controller.d.cts +11 -4
- package/dist/paint-editor/controller.d.ts +11 -4
- package/dist/paint-editor/dab-stroke.d.cts +2 -0
- package/dist/paint-editor/dab-stroke.d.ts +2 -0
- package/dist/paint-editor/engine.d.cts +11 -2
- package/dist/paint-editor/engine.d.ts +11 -2
- package/dist/paint-editor/index.cjs +967 -2335
- package/dist/paint-editor/index.d.cts +3 -1
- package/dist/paint-editor/index.d.ts +3 -1
- package/dist/paint-editor/index.js +394 -1762
- package/dist/paint-editor/path-samples.d.cts +2 -0
- package/dist/paint-editor/path-samples.d.ts +2 -0
- package/dist/paint-editor/presence.d.cts +20 -1
- package/dist/paint-editor/presence.d.ts +20 -1
- package/dist/paint-editor/stamp-tip.d.cts +8 -5
- package/dist/paint-editor/stamp-tip.d.ts +8 -5
- package/dist/paint-editor/thumbnails.d.cts +6 -0
- package/dist/paint-editor/thumbnails.d.ts +6 -0
- package/dist/paint-editor/tip-grain.d.cts +34 -0
- package/dist/paint-editor/tip-grain.d.ts +34 -0
- package/dist/raster/index.cjs +2 -2
- package/dist/raster/index.js +9 -9
- package/dist/stickers/helpers.d.cts +2 -0
- package/dist/stickers/helpers.d.ts +2 -0
- package/dist/stickers/index.cjs +41 -35
- package/dist/stickers/index.js +22 -16
- package/dist/stickers/types.d.cts +4 -2
- package/dist/stickers/types.d.ts +4 -2
- package/dist/vector/backdrop.d.cts +13 -0
- package/dist/vector/backdrop.d.ts +13 -0
- package/dist/vector/brushstroke.d.cts +54 -7
- package/dist/vector/brushstroke.d.ts +54 -7
- package/dist/vector/brushstrokeMedia.d.cts +96 -0
- package/dist/vector/brushstrokeMedia.d.ts +96 -0
- package/dist/vector/controller.d.cts +17 -3
- package/dist/vector/controller.d.ts +17 -3
- package/dist/vector/index.cjs +1850 -1390
- package/dist/vector/index.d.cts +2 -0
- package/dist/vector/index.d.ts +2 -0
- package/dist/vector/index.js +520 -60
- package/dist/vector/render.d.cts +6 -0
- package/dist/vector/render.d.ts +6 -0
- package/dist/vector/types.d.cts +14 -0
- package/dist/vector/types.d.ts +14 -0
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +1 -0
- package/skills/pixerate-brushes/SKILL.md +37 -10
- package/skills/pixerate-brushes-design/SKILL.md +15 -5
- package/skills/pixerate-brushes-design/evals/port-to-vector.json +8 -8
- package/skills/pixerate-canvas/SKILL.md +11 -1
- package/skills/pixerate-image-editor/SKILL.md +19 -64
- package/skills/pixerate-image-editor/references/color-management.md +2 -1
- package/skills/pixerate-image-editor/references/free-transform.md +12 -0
- package/skills/pixerate-image-editor/references/layer-effects.md +10 -0
- package/skills/pixerate-image-editor/references/painting.md +17 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +1 -1
- package/skills/pixerate-image-editor/references/shapes-and-type.md +14 -0
- package/skills/pixerate-image-editor/references/smart-objects.md +10 -0
- package/skills/pixerate-paint-editor/SKILL.md +14 -4
- package/skills/pixerate-paint-editor/references/brush-facets.md +3 -1
- package/skills/pixerate-paint-editor/references/wet-media.md +9 -0
- package/skills/pixerate-paint-sketch-to-finish/SKILL.md +1 -0
- package/skills/pixerate-vector/SKILL.md +16 -6
- package/skills/pixerate-vector/references/best-practices.md +1 -0
- package/skills/pixerate-vector/references/commands.md +19 -0
package/dist/brushes/index.js
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
createBrushLibraryToolProvider,
|
|
9
9
|
createBrushLibraryTools,
|
|
10
10
|
mergeBrushPatch
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-3XDSNIGF.js";
|
|
12
|
+
import "../chunk-VE6UKYQ2.js";
|
|
13
13
|
import {
|
|
14
14
|
BRUSH_PREVIEW_DARK_PAPER,
|
|
15
15
|
BRUSH_PREVIEW_FALLBACKS,
|
|
@@ -17,62 +17,84 @@ import {
|
|
|
17
17
|
brushPreviewColours,
|
|
18
18
|
brushPreviewStrength,
|
|
19
19
|
brushPreviewsOnDark
|
|
20
|
-
} from "../chunk-
|
|
20
|
+
} from "../chunk-LETF75CA.js";
|
|
21
21
|
import {
|
|
22
22
|
BRUSH_FACET_SCHEMAS,
|
|
23
23
|
BRUSH_FIELDS,
|
|
24
|
+
BRUSH_FLIPS,
|
|
25
|
+
BRUSH_GRAIN_MODES,
|
|
26
|
+
BRUSH_GRAIN_SOURCE_PATTERN,
|
|
24
27
|
BRUSH_HOST_PROFILES,
|
|
28
|
+
BRUSH_ID,
|
|
25
29
|
BRUSH_JSON_SCHEMA,
|
|
26
30
|
BRUSH_KINDS,
|
|
27
31
|
BRUSH_MARKS_KINDS,
|
|
28
32
|
BRUSH_MEDIA,
|
|
29
33
|
BRUSH_PRESETS,
|
|
30
34
|
BRUSH_ROTATIONS,
|
|
35
|
+
BRUSH_SOURCE_CHANNELS,
|
|
36
|
+
BRUSH_SOURCE_PROVIDER,
|
|
31
37
|
BRUSH_SURFACES,
|
|
32
38
|
BRUSH_TIP_SHAPES,
|
|
33
39
|
BRUSH_TOOLS,
|
|
34
40
|
BRUSH_WORD,
|
|
35
41
|
BUILTIN_BRUSHES,
|
|
36
42
|
BrushLibraryError,
|
|
43
|
+
BrushSourceError,
|
|
37
44
|
CANVAS_PROFILE,
|
|
38
45
|
DOT_ROTATIONS,
|
|
39
46
|
DOT_TEXTURE_ORDERS,
|
|
40
47
|
IMAGE_PROFILE,
|
|
41
48
|
IMPASTO_TOOLS,
|
|
42
49
|
MAX_BRUSH_PALETTE,
|
|
50
|
+
MAX_BRUSH_SOURCES,
|
|
51
|
+
MAX_BRUSH_SOURCE_INPUT_PIXELS,
|
|
52
|
+
MAX_BRUSH_SOURCE_SIZE,
|
|
43
53
|
MAX_DOT_TEXTURES,
|
|
44
54
|
MAX_STICKER_STAMPS,
|
|
45
55
|
PAINT_PROFILE,
|
|
46
56
|
PARTICLE_KINDS,
|
|
47
57
|
PARTICLE_RENDERS,
|
|
48
58
|
RIBBON_PAIRS,
|
|
59
|
+
TIP_GRAIN_PATTERNS,
|
|
49
60
|
VECTOR_PROFILE,
|
|
50
61
|
WET_BRUSH_TOOLS,
|
|
51
62
|
WET_MEDIA,
|
|
52
63
|
brushColourKind,
|
|
64
|
+
brushSourceFromMask,
|
|
65
|
+
brushSourceIdFromName,
|
|
66
|
+
brushSourceIdOf,
|
|
67
|
+
brushSourceIds,
|
|
68
|
+
brushSourceRef,
|
|
53
69
|
brushToJSON,
|
|
54
70
|
checkBrush,
|
|
55
71
|
checkBrushEdit,
|
|
56
72
|
createBrushLibrary,
|
|
73
|
+
decodeBrushSource,
|
|
57
74
|
degrade,
|
|
58
75
|
getPath,
|
|
59
76
|
isBrushLibrary,
|
|
77
|
+
isBrushSourceRef,
|
|
60
78
|
listPresets,
|
|
79
|
+
makeBrushSource,
|
|
61
80
|
migrateBrushV1,
|
|
62
81
|
normalizeBrushSpec,
|
|
63
82
|
normalizePaintBrush,
|
|
64
83
|
parseBrushLibrary2 as parseBrushLibrary,
|
|
84
|
+
parseBrushLibrarySources,
|
|
85
|
+
readBrushSource,
|
|
65
86
|
resolveBrush,
|
|
66
87
|
resolveCategory,
|
|
67
88
|
resolveEngine,
|
|
68
89
|
resolveWetMedium,
|
|
69
90
|
setPath,
|
|
70
91
|
snapshotBrushLibrary,
|
|
92
|
+
summarizeBrushSource,
|
|
71
93
|
withKeptIssues
|
|
72
|
-
} from "../chunk-
|
|
94
|
+
} from "../chunk-KZI3YWKW.js";
|
|
73
95
|
import {
|
|
74
96
|
STAMP_KINDS
|
|
75
|
-
} from "../chunk-
|
|
97
|
+
} from "../chunk-JL6YH5WD.js";
|
|
76
98
|
import {
|
|
77
99
|
brushColourHex
|
|
78
100
|
} from "../chunk-DVPQFMH6.js";
|
|
@@ -80,12 +102,17 @@ import "../chunk-SZTI6EER.js";
|
|
|
80
102
|
import "../chunk-V2ZCJRDM.js";
|
|
81
103
|
import {
|
|
82
104
|
MAX_BRUSH_SIZE
|
|
83
|
-
} from "../chunk-
|
|
105
|
+
} from "../chunk-ACTHSQOI.js";
|
|
84
106
|
import "../chunk-4D6KP5BV.js";
|
|
85
107
|
import {
|
|
86
108
|
BLEND_MODES
|
|
87
109
|
} from "../chunk-IRSTHLQQ.js";
|
|
110
|
+
import {
|
|
111
|
+
bytesToBase64,
|
|
112
|
+
isPng
|
|
113
|
+
} from "../chunk-OTTT5N3K.js";
|
|
88
114
|
import "../chunk-HVVR5PZW.js";
|
|
115
|
+
import "../chunk-QGHEDC7B.js";
|
|
89
116
|
import {
|
|
90
117
|
isDualColor
|
|
91
118
|
} from "../chunk-VR6OGHU5.js";
|
|
@@ -107,6 +134,9 @@ var RENDER_LABELS = { dot: "Dots", line: "Lines", sequence: "Beads", ribbon: "Ri
|
|
|
107
134
|
var APPLICATOR_LABELS = { brush: "Brush", tube: "Paint tube", knife: "Palette knife", roller: "Roller", gloop: "Gloop pen" };
|
|
108
135
|
var WET_MEDIUM_LABELS = { watercolor: "Watercolour", gouache: "Gouache", oil: "Oil" };
|
|
109
136
|
var STAMP_OPTIONS = STAMP_KINDS.map((k) => ({ value: `editor:${k}`, label: title(k) }));
|
|
137
|
+
var GRAIN_MODE_LABELS = { texturised: "Texturised (stays put)", moving: "Moving (rolls with the tip)" };
|
|
138
|
+
var FLIP_LABELS = { none: "None", x: "Across", y: "Along", xy: "Both" };
|
|
139
|
+
var DAB_ENGINES = /* @__PURE__ */ new Set(["dab", "eraser", "mixer", "blender", "smudge"]);
|
|
110
140
|
var ARIA = {
|
|
111
141
|
"dynamics.rotation": "Brush rotation",
|
|
112
142
|
"tip.blend": "Brush blend",
|
|
@@ -119,10 +149,12 @@ var ARIA = {
|
|
|
119
149
|
"marks.stampRotation": "Dot rotation",
|
|
120
150
|
"behaviour.wet.medium": "Wet medium",
|
|
121
151
|
"behaviour.thick.applicator": "Impasto tool",
|
|
122
|
-
"light.pressure": "Light follows pressure"
|
|
152
|
+
"light.pressure": "Light follows pressure",
|
|
153
|
+
"tip.grain.source": "Tip grain",
|
|
154
|
+
"dynamics.angleJitter": "Brush rotation jitter"
|
|
123
155
|
};
|
|
124
156
|
var aria = (path, label) => ARIA[path] ?? `Brush ${label.toLowerCase()}`;
|
|
125
|
-
function brushEditorSections(brush, profile = PAINT_PROFILE) {
|
|
157
|
+
function brushEditorSections(brush, profile = PAINT_PROFILE, context = {}) {
|
|
126
158
|
const resolved = resolveBrush(brush);
|
|
127
159
|
const engine = resolveEngine(brush);
|
|
128
160
|
const fieldOf = (facet) => BRUSH_FIELDS.find((f) => f.facet === facet && f.engines.includes(engine));
|
|
@@ -160,6 +192,7 @@ function brushEditorSections(brush, profile = PAINT_PROFILE) {
|
|
|
160
192
|
};
|
|
161
193
|
const isTool = brush.kind === "tool";
|
|
162
194
|
const shape = brush.tip.shape;
|
|
195
|
+
const sourceOptions = (context.sources ?? []).map((x) => ({ value: brushSourceRef(x.id), label: x.name }));
|
|
163
196
|
const marks = brush.marks?.kind ?? "continuous";
|
|
164
197
|
const exchangeFull = full(brush.behaviour?.exchange?.reservoir ? profile.reservoir : profile.exchange);
|
|
165
198
|
add("medium", "Medium", [
|
|
@@ -175,8 +208,20 @@ function brushEditorSections(brush, profile = PAINT_PROFILE) {
|
|
|
175
208
|
...tipSliders.map((c) => slider(c)),
|
|
176
209
|
engine === "dab" && choice("tip.blend", "Blend", BLEND_MODES.map((m) => ({ value: m.id, label: m.label })), "normal"),
|
|
177
210
|
...shape === "bristle" && engineOk && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("bristle.")).map((c) => slider(c)) : [],
|
|
178
|
-
shape === "stamp" && engineOk && withNote({ kind: "stamps", path: "tip.stamps", label: "Stamps", ariaLabel: "Brush stamps", value: [...value("tip.stamps") ?? []], max: marks === "particles" ? MAX_DOT_TEXTURES : MAX_STICKER_STAMPS, options: STAMP_OPTIONS })
|
|
211
|
+
shape === "stamp" && engineOk && withNote({ kind: "stamps", path: "tip.stamps", label: "Stamps", ariaLabel: "Brush stamps", value: [...value("tip.stamps") ?? []], max: marks === "particles" ? MAX_DOT_TEXTURES : MAX_STICKER_STAMPS, options: marks === "objects" ? STAMP_OPTIONS : [...STAMP_OPTIONS, ...sourceOptions] })
|
|
179
212
|
]);
|
|
213
|
+
const dabs = DAB_ENGINES.has(engine) && engineOk && shape !== "bristle" && marks !== "particles" && marks !== "objects";
|
|
214
|
+
const grain = brush.tip.grain;
|
|
215
|
+
if (dabs && full(profile.tipGrain ?? "none")) {
|
|
216
|
+
add("grain", "Tip grain", [
|
|
217
|
+
choice("tip.grain.source", "Texture", [{ value: "", label: "None" }, ...options(TIP_GRAIN_PATTERNS), ...sourceOptions], ""),
|
|
218
|
+
!!grain && choice("tip.grain.mode", "Grain moves", options(BRUSH_GRAIN_MODES, GRAIN_MODE_LABELS), "texturised"),
|
|
219
|
+
!!grain && withNote({ kind: "slider", path: "tip.grain.scale", label: "Grain scale", ariaLabel: "Brush grain scale", min: 0.1, max: 8, step: 0.05, value: grain.scale ?? 1 }),
|
|
220
|
+
!!grain && withNote({ kind: "slider", path: "tip.grain.depth", label: "Grain depth", ariaLabel: "Brush grain depth", min: 0, max: 1, step: 0.01, value: grain.depth ?? 0.6 }),
|
|
221
|
+
!!grain && withNote({ kind: "slider", path: "tip.grain.contrast", label: "Grain contrast", ariaLabel: "Brush grain contrast", min: 0, max: 3, step: 0.05, value: grain.contrast ?? 1 }),
|
|
222
|
+
!!grain && toggle("tip.grain.invert", "Invert grain")
|
|
223
|
+
]);
|
|
224
|
+
}
|
|
180
225
|
if (!isTool && profile.marks.length > 1 && engineOk) {
|
|
181
226
|
const particles = marks === "particles" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("particle.") && c.path !== "particle.waveSpeed") : [];
|
|
182
227
|
const objects = marks === "objects" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("sticker.")) : [];
|
|
@@ -193,11 +238,18 @@ function brushEditorSections(brush, profile = PAINT_PROFILE) {
|
|
|
193
238
|
]);
|
|
194
239
|
}
|
|
195
240
|
const feel = BRUSH_SLIDERS.filter((c) => ["tip.smoothing", "pressureSmoothing", "dynamics.minSize", "dynamics.tiltSize", "dynamics.velocitySize"].includes(c.path)).filter((c) => !(c.path === "dynamics.tiltSize" && !full(profile.tilt)) && !(c.path === "dynamics.velocitySize" && !full(profile.velocity)));
|
|
241
|
+
const stampDabs = dabs && shape === "stamp";
|
|
242
|
+
const jitter = (path, label, max = 1, step = 0.01) => withNote({ kind: "slider", path, label, ariaLabel: aria(path, label), min: 0, max, step, value: Number(value(path) ?? 0) });
|
|
196
243
|
add("feel", "Feel", [
|
|
197
244
|
...feel.map((c) => slider(c)),
|
|
198
245
|
toggle("dynamics.pressureSize", "Pressure \u2192 size"),
|
|
199
246
|
toggle("dynamics.pressureOpacity", "Pressure \u2192 opacity"),
|
|
200
|
-
choice("dynamics.rotation", "Rotation", options(BRUSH_ROTATIONS, ROTATION_LABELS))
|
|
247
|
+
choice("dynamics.rotation", "Rotation", options(BRUSH_ROTATIONS, ROTATION_LABELS)),
|
|
248
|
+
stampDabs && full(profile.dabCount ?? "none") && withNote({ kind: "slider", path: "dynamics.count", label: "Count", ariaLabel: "Brush dab count", min: 1, max: 16, step: 1, value: brush.dynamics?.count ?? 1 }),
|
|
249
|
+
stampDabs && jitter("dynamics.scatter", "Scatter", 4),
|
|
250
|
+
stampDabs && jitter("dynamics.angleJitter", "Rotation jitter"),
|
|
251
|
+
stampDabs && jitter("dynamics.sizeJitter", "Size jitter"),
|
|
252
|
+
stampDabs && choice("dynamics.flip", "Flip", options(BRUSH_FLIPS, FLIP_LABELS), "none")
|
|
201
253
|
]);
|
|
202
254
|
const surfaces = profile.surfaces;
|
|
203
255
|
const engineSliders = (engineOk ? engineControls?.sliders ?? [] : []).filter((c) => !/^(bristle|particle|sticker)\./.test(c.path) && c.path !== "light.amount" && c.path !== "impasto.rim" && c.path !== "impasto.clarity");
|
|
@@ -259,6 +311,10 @@ function hiddenLabel(issue, b) {
|
|
|
259
311
|
return "paint pick-up";
|
|
260
312
|
case "behaviour.grain":
|
|
261
313
|
return "paper grain";
|
|
314
|
+
case "tip.grain":
|
|
315
|
+
return "tip grain";
|
|
316
|
+
case "dynamics.count":
|
|
317
|
+
return "several dabs per step";
|
|
262
318
|
case "light":
|
|
263
319
|
return "light";
|
|
264
320
|
case "motion":
|
|
@@ -330,6 +386,8 @@ function setBrushEditorValue(brush, path, value) {
|
|
|
330
386
|
next.marks = value === "continuous" ? void 0 : { kind: value };
|
|
331
387
|
if (value !== "continuous" && next.tip.shape === "bristle") next.tip = { ...next.tip, shape: "round", bristle: void 0 };
|
|
332
388
|
if (value === "objects") next.tip = { ...next.tip, shape: "stamp" };
|
|
389
|
+
} else if (path === "tip.grain.source" && (value === void 0 || value === "")) {
|
|
390
|
+
delete next.tip.grain;
|
|
333
391
|
} else if (path === "tip.shape" && value !== "stamp") {
|
|
334
392
|
next.tip = { ...next.tip, shape: value, stamps: void 0 };
|
|
335
393
|
if (value !== "bristle") delete next.tip.bristle;
|
|
@@ -369,6 +427,28 @@ function brushLibraryGroups(entries, filter = {}) {
|
|
|
369
427
|
const order = ["dry", "ink", "paint", "spray", "other", "tools"];
|
|
370
428
|
return [...groups.values()].sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
|
|
371
429
|
}
|
|
430
|
+
async function imageFileToPngDataUrl(file) {
|
|
431
|
+
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
432
|
+
if (isPng(bytes)) return `data:image/png;base64,${bytesToBase64(bytes)}`;
|
|
433
|
+
const g = globalThis;
|
|
434
|
+
if (!g.createImageBitmap || !g.OffscreenCanvas) throw new BrushSourceError("Only PNG images can be read here; convert the image to PNG.");
|
|
435
|
+
const bitmap = await g.createImageBitmap(file);
|
|
436
|
+
const canvas = new g.OffscreenCanvas(bitmap.width, bitmap.height);
|
|
437
|
+
canvas.getContext("2d").drawImage(bitmap, 0, 0);
|
|
438
|
+
const png = new Uint8Array(await (await canvas.convertToBlob({ type: "image/png" })).arrayBuffer());
|
|
439
|
+
return `data:image/png;base64,${bytesToBase64(png)}`;
|
|
440
|
+
}
|
|
441
|
+
async function addBrushSourceFromFile(library, file, options2 = {}) {
|
|
442
|
+
const name = (options2.name ?? file.name?.replace(/\.[a-z0-9]+$/i, "") ?? "Image").trim() || "Image";
|
|
443
|
+
const result = await library.addSource({ name, image: await imageFileToPngDataUrl(file), origin: file.name, ...options2.channel ? { channel: options2.channel } : {} });
|
|
444
|
+
return { ...result, ref: brushSourceRef(result.source.id) };
|
|
445
|
+
}
|
|
446
|
+
function withBrushSource(brush, ref, as) {
|
|
447
|
+
if (as === "grain") return setBrushEditorValue(brush, "tip.grain.source", ref);
|
|
448
|
+
const stamp = brush.tip.shape === "stamp" ? { brush, problems: [] } : setBrushEditorValue(brush, "tip.shape", "stamp");
|
|
449
|
+
const r = setBrushEditorValue(stamp.brush, "tip.stamps", [ref]);
|
|
450
|
+
return { brush: r.brush, problems: [...stamp.problems, ...r.problems] };
|
|
451
|
+
}
|
|
372
452
|
|
|
373
453
|
// src/brushes/contract.ts
|
|
374
454
|
var BRUSH_CONTRACT_FORMAT_VERSION = 1;
|
|
@@ -391,7 +471,9 @@ var BRUSH_PROFILE_JSON_SCHEMA = {
|
|
|
391
471
|
motion: { ...SUPPORT, description: "Motion after painting." },
|
|
392
472
|
colours: { type: "array", items: { type: "string", enum: ["solid", "dual", "gradient", "effect"] }, description: "Colour kinds a default colour may be." },
|
|
393
473
|
velocity: { ...SUPPORT, description: "Velocity dynamics." },
|
|
394
|
-
tilt: { ...SUPPORT, description: "Tilt dynamics." }
|
|
474
|
+
tilt: { ...SUPPORT, description: "Tilt dynamics." },
|
|
475
|
+
tipGrain: { ...SUPPORT, description: "Texture inside the tip (tip.grain); missing: none." },
|
|
476
|
+
dabCount: { ...SUPPORT, description: "Several dabs per spacing step (dynamics.count); missing: none." }
|
|
395
477
|
},
|
|
396
478
|
required: ["id", "name", "kinds", "tools", "tipShapes", "marks", "surfaces", "exchange", "reservoir", "grain", "light", "motion", "colours", "velocity", "tilt"],
|
|
397
479
|
additionalProperties: false
|
|
@@ -402,7 +484,27 @@ var BRUSH_LIBRARY_FILE_JSON_SCHEMA = {
|
|
|
402
484
|
properties: {
|
|
403
485
|
format: { type: "string", const: "pixerate-brushes", description: 'Always "pixerate-brushes".' },
|
|
404
486
|
version: { type: "integer", const: 2, description: "Always 2." },
|
|
405
|
-
brushes: { type: "array", items: { $ref: "brush.schema.json" }, description: "The brushes, each a facet brush (brush.schema.json)." }
|
|
487
|
+
brushes: { type: "array", items: { $ref: "brush.schema.json" }, description: "The brushes, each a facet brush (brush.schema.json)." },
|
|
488
|
+
sources: {
|
|
489
|
+
type: "array",
|
|
490
|
+
maxItems: MAX_BRUSH_SOURCES,
|
|
491
|
+
description: "The image sources the brushes name (source:<id> in tip.stamps or tip.grain.source), bytes included.",
|
|
492
|
+
items: {
|
|
493
|
+
type: "object",
|
|
494
|
+
description: "An image source: a grey mask, 255 paints (or is a grain peak).",
|
|
495
|
+
properties: {
|
|
496
|
+
id: { type: "string", pattern: BRUSH_ID.source, description: "Source id." },
|
|
497
|
+
name: { type: "string", maxLength: 80, description: "Display name." },
|
|
498
|
+
width: { type: "integer", minimum: 1, maximum: MAX_BRUSH_SOURCE_SIZE, description: "Width in px." },
|
|
499
|
+
height: { type: "integer", minimum: 1, maximum: MAX_BRUSH_SOURCE_SIZE, description: "Height in px." },
|
|
500
|
+
image: { type: "string", pattern: "^data:image/png;base64,", description: "The mask as a greyscale PNG data: URL." },
|
|
501
|
+
licence: { type: "string", maxLength: 2e3, description: "The licence or terms it came with." },
|
|
502
|
+
origin: { type: "string", maxLength: 200, description: "Where it came from (a file or pack name)." }
|
|
503
|
+
},
|
|
504
|
+
required: ["id", "name", "width", "height", "image"],
|
|
505
|
+
additionalProperties: false
|
|
506
|
+
}
|
|
507
|
+
}
|
|
406
508
|
},
|
|
407
509
|
required: ["format", "version", "brushes"],
|
|
408
510
|
additionalProperties: false
|
|
@@ -480,6 +582,9 @@ function brushContracts() {
|
|
|
480
582
|
export {
|
|
481
583
|
BRUSH_CONTRACT_FORMAT_VERSION,
|
|
482
584
|
BRUSH_FACET_SCHEMAS,
|
|
585
|
+
BRUSH_FLIPS,
|
|
586
|
+
BRUSH_GRAIN_MODES,
|
|
587
|
+
BRUSH_GRAIN_SOURCE_PATTERN,
|
|
483
588
|
BRUSH_HOST_PROFILES,
|
|
484
589
|
BRUSH_JSON_SCHEMA,
|
|
485
590
|
BRUSH_KINDS,
|
|
@@ -492,19 +597,27 @@ export {
|
|
|
492
597
|
BRUSH_PREVIEW_FALLBACKS,
|
|
493
598
|
BRUSH_PREVIEW_MIN_CONTRAST,
|
|
494
599
|
BRUSH_PROFILE_JSON_SCHEMA,
|
|
600
|
+
BRUSH_SOURCE_CHANNELS,
|
|
601
|
+
BRUSH_SOURCE_PROVIDER,
|
|
495
602
|
BRUSH_SURFACES,
|
|
496
603
|
BRUSH_TIP_SHAPES,
|
|
497
604
|
BRUSH_TOOLS,
|
|
498
605
|
BRUSH_UNSET_PROPERTY,
|
|
499
606
|
BRUSH_WORD,
|
|
500
607
|
BrushLibraryError,
|
|
608
|
+
BrushSourceError,
|
|
501
609
|
CANVAS_PROFILE,
|
|
502
610
|
IMAGE_PROFILE,
|
|
503
611
|
MAX_BRUSH_PALETTE,
|
|
612
|
+
MAX_BRUSH_SOURCES,
|
|
613
|
+
MAX_BRUSH_SOURCE_INPUT_PIXELS,
|
|
614
|
+
MAX_BRUSH_SOURCE_SIZE,
|
|
504
615
|
PAINT_PROFILE,
|
|
616
|
+
TIP_GRAIN_PATTERNS,
|
|
505
617
|
UNSETTABLE_BRUSH_FACETS,
|
|
506
618
|
VECTOR_PROFILE,
|
|
507
619
|
WET_BRUSH_TOOLS,
|
|
620
|
+
addBrushSourceFromFile,
|
|
508
621
|
brushColourHex,
|
|
509
622
|
brushColourKind,
|
|
510
623
|
brushContracts,
|
|
@@ -515,20 +628,31 @@ export {
|
|
|
515
628
|
brushPreviewColours,
|
|
516
629
|
brushPreviewStrength,
|
|
517
630
|
brushPreviewsOnDark,
|
|
631
|
+
brushSourceFromMask,
|
|
632
|
+
brushSourceIdFromName,
|
|
633
|
+
brushSourceIdOf,
|
|
634
|
+
brushSourceIds,
|
|
635
|
+
brushSourceRef,
|
|
518
636
|
changedBrushPaths,
|
|
519
637
|
checkBrush,
|
|
520
638
|
checkBrushEdit,
|
|
521
639
|
createBrushLibrary,
|
|
522
640
|
createBrushLibraryToolProvider,
|
|
523
641
|
createBrushLibraryTools,
|
|
642
|
+
decodeBrushSource,
|
|
524
643
|
degrade,
|
|
644
|
+
imageFileToPngDataUrl,
|
|
525
645
|
isBrushLibrary,
|
|
646
|
+
isBrushSourceRef,
|
|
526
647
|
listPresets,
|
|
648
|
+
makeBrushSource,
|
|
527
649
|
mergeBrushPatch,
|
|
528
650
|
migrateBrushV1,
|
|
529
651
|
newBrushFor,
|
|
530
652
|
normalizeBrushSpec,
|
|
531
653
|
parseBrushLibrary,
|
|
654
|
+
parseBrushLibrarySources,
|
|
655
|
+
readBrushSource,
|
|
532
656
|
resolveBrush,
|
|
533
657
|
resolveCategory,
|
|
534
658
|
resolveEngine,
|
|
@@ -536,5 +660,7 @@ export {
|
|
|
536
660
|
saveBrushEdit,
|
|
537
661
|
setBrushEditorValue,
|
|
538
662
|
snapshotBrushLibrary,
|
|
663
|
+
summarizeBrushSource,
|
|
664
|
+
withBrushSource,
|
|
539
665
|
withKeptIssues
|
|
540
666
|
};
|
|
@@ -9,14 +9,17 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { StorageAdapter } from '../persistence/storage.cjs';
|
|
11
11
|
import { type BrushHostProfile } from './profiles.cjs';
|
|
12
|
+
import { type BrushSource, type BrushSourceInput } from './sources.cjs';
|
|
12
13
|
import type { Brush, BrushKind, BrushMedium, BrushTool } from './types.cjs';
|
|
13
14
|
/** The JSON file a brush library exports to and imports from. */
|
|
14
15
|
export interface BrushLibraryFile {
|
|
15
16
|
format: 'pixerate-brushes';
|
|
16
17
|
version: 2;
|
|
17
18
|
brushes: Brush[];
|
|
19
|
+
/** The image sources the brushes lay or texture with (`source:<id>`), bytes included. */
|
|
20
|
+
sources?: BrushSource[];
|
|
18
21
|
}
|
|
19
|
-
export type BrushLibraryErrorCode = 'unknown_brush' | 'builtin' | 'exists' | 'invalid';
|
|
22
|
+
export type BrushLibraryErrorCode = 'unknown_brush' | 'unknown_source' | 'builtin' | 'exists' | 'invalid';
|
|
20
23
|
/** A refusal; the message says what to do instead. */
|
|
21
24
|
export declare class BrushLibraryError extends Error {
|
|
22
25
|
readonly code: BrushLibraryErrorCode;
|
|
@@ -54,6 +57,16 @@ export interface ImportBrushesResult {
|
|
|
54
57
|
replaced: string[];
|
|
55
58
|
skipped: string[];
|
|
56
59
|
problems: string[];
|
|
60
|
+
/** Image sources added or replaced (only when there were any). */
|
|
61
|
+
sources?: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface AddBrushSourceResult {
|
|
64
|
+
/** The source as stored. */
|
|
65
|
+
source: BrushSource;
|
|
66
|
+
/** What reading the image changed (the channel picked, scaling). */
|
|
67
|
+
problems: string[];
|
|
68
|
+
/** It replaced a source of the same id. */
|
|
69
|
+
replaced: boolean;
|
|
57
70
|
}
|
|
58
71
|
export interface BrushLibraryOptions {
|
|
59
72
|
/** Where the user's brushes are kept (default: memory only, gone on reload). */
|
|
@@ -88,11 +101,24 @@ export interface BrushLibrary {
|
|
|
88
101
|
importFile(raw: unknown, options?: {
|
|
89
102
|
overwrite?: boolean;
|
|
90
103
|
}): Promise<ImportBrushesResult>;
|
|
104
|
+
/** The image sources brushes lay (`tip.stamps` `source:<id>`) or texture with (`tip.grain.source`), in the order added. */
|
|
105
|
+
listSources(): Promise<BrushSource[]>;
|
|
106
|
+
getSource(id: string): Promise<BrushSource | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Stores an image source: an uploaded image (`BrushSourceInput`, read by `makeBrushSource`) or a
|
|
109
|
+
* source as stored. Without an id it gets one from its name; a taken id is refused unless
|
|
110
|
+
* `overwrite`.
|
|
111
|
+
*/
|
|
112
|
+
addSource(input: BrushSourceInput | BrushSource, options?: {
|
|
113
|
+
overwrite?: boolean;
|
|
114
|
+
}): Promise<AddBrushSourceResult>;
|
|
91
115
|
/** Called after every change. Returns an unsubscribe function. */
|
|
92
116
|
subscribe(listener: () => void): () => void;
|
|
93
117
|
}
|
|
94
118
|
/** Whether `library` is a whole `BrushLibrary` (it can save), not only a list to read: hosts offer brush editing on one. */
|
|
95
119
|
export declare function isBrushLibrary(library: unknown): library is BrushLibrary;
|
|
120
|
+
/** The image sources of a library file (`sources`), each checked; bad ones are skipped and reported. */
|
|
121
|
+
export declare function parseBrushLibrarySources(raw: unknown, problems?: string[]): BrushSource[];
|
|
96
122
|
/**
|
|
97
123
|
* Brushes read from a library file: `{ format: 'pixerate-brushes', version: 1 | 2, brushes }` or
|
|
98
124
|
* a bare array. Version 1 brushes are migrated (`migrateBrushV1`); every brush is normalised.
|
|
@@ -9,14 +9,17 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { StorageAdapter } from '../persistence/storage.js';
|
|
11
11
|
import { type BrushHostProfile } from './profiles.js';
|
|
12
|
+
import { type BrushSource, type BrushSourceInput } from './sources.js';
|
|
12
13
|
import type { Brush, BrushKind, BrushMedium, BrushTool } from './types.js';
|
|
13
14
|
/** The JSON file a brush library exports to and imports from. */
|
|
14
15
|
export interface BrushLibraryFile {
|
|
15
16
|
format: 'pixerate-brushes';
|
|
16
17
|
version: 2;
|
|
17
18
|
brushes: Brush[];
|
|
19
|
+
/** The image sources the brushes lay or texture with (`source:<id>`), bytes included. */
|
|
20
|
+
sources?: BrushSource[];
|
|
18
21
|
}
|
|
19
|
-
export type BrushLibraryErrorCode = 'unknown_brush' | 'builtin' | 'exists' | 'invalid';
|
|
22
|
+
export type BrushLibraryErrorCode = 'unknown_brush' | 'unknown_source' | 'builtin' | 'exists' | 'invalid';
|
|
20
23
|
/** A refusal; the message says what to do instead. */
|
|
21
24
|
export declare class BrushLibraryError extends Error {
|
|
22
25
|
readonly code: BrushLibraryErrorCode;
|
|
@@ -54,6 +57,16 @@ export interface ImportBrushesResult {
|
|
|
54
57
|
replaced: string[];
|
|
55
58
|
skipped: string[];
|
|
56
59
|
problems: string[];
|
|
60
|
+
/** Image sources added or replaced (only when there were any). */
|
|
61
|
+
sources?: string[];
|
|
62
|
+
}
|
|
63
|
+
export interface AddBrushSourceResult {
|
|
64
|
+
/** The source as stored. */
|
|
65
|
+
source: BrushSource;
|
|
66
|
+
/** What reading the image changed (the channel picked, scaling). */
|
|
67
|
+
problems: string[];
|
|
68
|
+
/** It replaced a source of the same id. */
|
|
69
|
+
replaced: boolean;
|
|
57
70
|
}
|
|
58
71
|
export interface BrushLibraryOptions {
|
|
59
72
|
/** Where the user's brushes are kept (default: memory only, gone on reload). */
|
|
@@ -88,11 +101,24 @@ export interface BrushLibrary {
|
|
|
88
101
|
importFile(raw: unknown, options?: {
|
|
89
102
|
overwrite?: boolean;
|
|
90
103
|
}): Promise<ImportBrushesResult>;
|
|
104
|
+
/** The image sources brushes lay (`tip.stamps` `source:<id>`) or texture with (`tip.grain.source`), in the order added. */
|
|
105
|
+
listSources(): Promise<BrushSource[]>;
|
|
106
|
+
getSource(id: string): Promise<BrushSource | null>;
|
|
107
|
+
/**
|
|
108
|
+
* Stores an image source: an uploaded image (`BrushSourceInput`, read by `makeBrushSource`) or a
|
|
109
|
+
* source as stored. Without an id it gets one from its name; a taken id is refused unless
|
|
110
|
+
* `overwrite`.
|
|
111
|
+
*/
|
|
112
|
+
addSource(input: BrushSourceInput | BrushSource, options?: {
|
|
113
|
+
overwrite?: boolean;
|
|
114
|
+
}): Promise<AddBrushSourceResult>;
|
|
91
115
|
/** Called after every change. Returns an unsubscribe function. */
|
|
92
116
|
subscribe(listener: () => void): () => void;
|
|
93
117
|
}
|
|
94
118
|
/** Whether `library` is a whole `BrushLibrary` (it can save), not only a list to read: hosts offer brush editing on one. */
|
|
95
119
|
export declare function isBrushLibrary(library: unknown): library is BrushLibrary;
|
|
120
|
+
/** The image sources of a library file (`sources`), each checked; bad ones are skipped and reported. */
|
|
121
|
+
export declare function parseBrushLibrarySources(raw: unknown, problems?: string[]): BrushSource[];
|
|
96
122
|
/**
|
|
97
123
|
* Brushes read from a library file: `{ format: 'pixerate-brushes', version: 1 | 2, brushes }` or
|
|
98
124
|
* a bare array. Version 1 brushes are migrated (`migrateBrushV1`); every brush is normalised.
|
|
@@ -35,6 +35,10 @@ export interface BrushHostProfile {
|
|
|
35
35
|
velocity: BrushSupport;
|
|
36
36
|
/** Tilt dynamics (needs pen tilt). */
|
|
37
37
|
tilt: BrushSupport;
|
|
38
|
+
/** Texture inside the tip (`tip.grain`); missing: `none`. */
|
|
39
|
+
tipGrain?: BrushSupport;
|
|
40
|
+
/** Several dabs per spacing step (`dynamics.count` above 1); missing: `none`. */
|
|
41
|
+
dabCount?: BrushSupport;
|
|
38
42
|
}
|
|
39
43
|
export interface BrushIssue {
|
|
40
44
|
/** The facet path the issue is about, e.g. `tip.shape`, `light`, `behaviour.exchange.reservoir`. */
|
|
@@ -58,7 +62,12 @@ export declare const IMAGE_PROFILE: BrushHostProfile;
|
|
|
58
62
|
* light channel (glow and spill), which canvas strokes don't have, so it is refused.
|
|
59
63
|
*/
|
|
60
64
|
export declare const CANVAS_PROFILE: BrushHostProfile;
|
|
61
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Vector brushstrokes: dab brushes along a path; light brushes paint as plain colour. Wet paint
|
|
67
|
+
* settles in its own small wet area and dries to a cached image; the Mixer Brush, smudge and
|
|
68
|
+
* blender act on the shapes beneath the stroke. The wet tools (water, hair dryer, blow, wet blend,
|
|
69
|
+
* wet drag, blot) act on wet paint, which a vector document never holds, so they are refused.
|
|
70
|
+
*/
|
|
62
71
|
export declare const VECTOR_PROFILE: BrushHostProfile;
|
|
63
72
|
/** The built-in profiles by id. */
|
|
64
73
|
export declare const BRUSH_HOST_PROFILES: Readonly<Record<string, BrushHostProfile>>;
|
|
@@ -35,6 +35,10 @@ export interface BrushHostProfile {
|
|
|
35
35
|
velocity: BrushSupport;
|
|
36
36
|
/** Tilt dynamics (needs pen tilt). */
|
|
37
37
|
tilt: BrushSupport;
|
|
38
|
+
/** Texture inside the tip (`tip.grain`); missing: `none`. */
|
|
39
|
+
tipGrain?: BrushSupport;
|
|
40
|
+
/** Several dabs per spacing step (`dynamics.count` above 1); missing: `none`. */
|
|
41
|
+
dabCount?: BrushSupport;
|
|
38
42
|
}
|
|
39
43
|
export interface BrushIssue {
|
|
40
44
|
/** The facet path the issue is about, e.g. `tip.shape`, `light`, `behaviour.exchange.reservoir`. */
|
|
@@ -58,7 +62,12 @@ export declare const IMAGE_PROFILE: BrushHostProfile;
|
|
|
58
62
|
* light channel (glow and spill), which canvas strokes don't have, so it is refused.
|
|
59
63
|
*/
|
|
60
64
|
export declare const CANVAS_PROFILE: BrushHostProfile;
|
|
61
|
-
/**
|
|
65
|
+
/**
|
|
66
|
+
* Vector brushstrokes: dab brushes along a path; light brushes paint as plain colour. Wet paint
|
|
67
|
+
* settles in its own small wet area and dries to a cached image; the Mixer Brush, smudge and
|
|
68
|
+
* blender act on the shapes beneath the stroke. The wet tools (water, hair dryer, blow, wet blend,
|
|
69
|
+
* wet drag, blot) act on wet paint, which a vector document never holds, so they are refused.
|
|
70
|
+
*/
|
|
62
71
|
export declare const VECTOR_PROFILE: BrushHostProfile;
|
|
63
72
|
/** The built-in profiles by id. */
|
|
64
73
|
export declare const BRUSH_HOST_PROFILES: Readonly<Record<string, BrushHostProfile>>;
|
|
@@ -10,11 +10,15 @@ export declare const MAX_BRUSH_PALETTE = 16;
|
|
|
10
10
|
export declare const BRUSH_WORD: RegExp;
|
|
11
11
|
/** A sticker ref `provider:id`, or a bare editor stamp (read as `editor:<stamp>`). */
|
|
12
12
|
export declare const BRUSH_STAMP_PATTERN: string;
|
|
13
|
+
/** Tip grain sources: the built-in patterns (not the flat `smooth`) or an image source `source:<id>`. */
|
|
14
|
+
export declare const TIP_GRAIN_PATTERNS: ("canvas" | "linen" | "cold-pressed" | "hot-pressed" | "rough" | "vellum" | "laid" | "ingres" | "sanded" | "gesso")[];
|
|
15
|
+
export declare const BRUSH_GRAIN_SOURCE_PATTERN: string;
|
|
13
16
|
/** JSON Schema of a `Brush`. */
|
|
14
17
|
export declare const BRUSH_JSON_SCHEMA: JsonSchema;
|
|
15
18
|
/** The facet schemas, for tools that take one facet. */
|
|
16
19
|
export declare const BRUSH_FACET_SCHEMAS: {
|
|
17
20
|
readonly tip: JsonSchema;
|
|
21
|
+
readonly tipGrain: JsonSchema;
|
|
18
22
|
readonly marks: {
|
|
19
23
|
readonly continuous: JsonSchema;
|
|
20
24
|
readonly scatter: JsonSchema;
|
package/dist/brushes/schema.d.ts
CHANGED
|
@@ -10,11 +10,15 @@ export declare const MAX_BRUSH_PALETTE = 16;
|
|
|
10
10
|
export declare const BRUSH_WORD: RegExp;
|
|
11
11
|
/** A sticker ref `provider:id`, or a bare editor stamp (read as `editor:<stamp>`). */
|
|
12
12
|
export declare const BRUSH_STAMP_PATTERN: string;
|
|
13
|
+
/** Tip grain sources: the built-in patterns (not the flat `smooth`) or an image source `source:<id>`. */
|
|
14
|
+
export declare const TIP_GRAIN_PATTERNS: ("canvas" | "linen" | "cold-pressed" | "hot-pressed" | "rough" | "vellum" | "laid" | "ingres" | "sanded" | "gesso")[];
|
|
15
|
+
export declare const BRUSH_GRAIN_SOURCE_PATTERN: string;
|
|
13
16
|
/** JSON Schema of a `Brush`. */
|
|
14
17
|
export declare const BRUSH_JSON_SCHEMA: JsonSchema;
|
|
15
18
|
/** The facet schemas, for tools that take one facet. */
|
|
16
19
|
export declare const BRUSH_FACET_SCHEMAS: {
|
|
17
20
|
readonly tip: JsonSchema;
|
|
21
|
+
readonly tipGrain: JsonSchema;
|
|
18
22
|
readonly marks: {
|
|
19
23
|
readonly continuous: JsonSchema;
|
|
20
24
|
readonly scatter: JsonSchema;
|