@pixerate/editor 0.251.0 → 0.253.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/brushes/index.cjs +240 -1344
- package/dist/brushes/index.d.cts +10 -1
- package/dist/brushes/index.d.ts +10 -1
- package/dist/brushes/index.js +250 -1354
- package/dist/brushes/library.d.cts +104 -0
- package/dist/brushes/library.d.ts +104 -0
- package/dist/brushes/patch.d.cts +23 -0
- package/dist/brushes/patch.d.ts +23 -0
- package/dist/brushes/profiles.d.cts +85 -0
- package/dist/brushes/profiles.d.ts +85 -0
- package/dist/brushes/tools.d.cts +37 -0
- package/dist/brushes/tools.d.ts +37 -0
- package/dist/brushes/ui.d.cts +105 -0
- package/dist/brushes/ui.d.ts +105 -0
- package/dist/chunk-34KLWUH4.cjs +2284 -0
- package/dist/chunk-QPHNVZHO.js +2284 -0
- package/dist/paint-editor/brush-controls.d.cts +57 -0
- package/dist/paint-editor/brush-controls.d.ts +57 -0
- package/dist/paint-editor/brush-library-tools.d.cts +15 -0
- package/dist/paint-editor/brush-library-tools.d.ts +15 -0
- package/dist/paint-editor/brush-library.d.cts +29 -0
- package/dist/paint-editor/brush-library.d.ts +29 -0
- package/dist/paint-editor/controller.d.cts +76 -17
- package/dist/paint-editor/controller.d.ts +76 -17
- package/dist/paint-editor/index.cjs +537 -852
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +327 -642
- package/dist/paint-editor/serialize.d.cts +7 -4
- package/dist/paint-editor/serialize.d.ts +7 -4
- package/dist/paint-editor/sticker-tools.d.cts +1 -1
- package/dist/paint-editor/sticker-tools.d.ts +1 -1
- package/dist/paint-editor/strokes.d.cts +10 -1
- package/dist/paint-editor/strokes.d.ts +10 -1
- package/dist/paint-editor/tools.d.cts +1 -1
- package/dist/paint-editor/tools.d.ts +1 -1
- package/dist/paint-editor/ui.d.cts +3 -51
- package/dist/paint-editor/ui.d.ts +3 -51
- package/dist/paint-editor/wet-tools.d.cts +1 -1
- package/dist/paint-editor/wet-tools.d.ts +1 -1
- package/dist/tools/skill-evals.d.cts +8 -1
- package/dist/tools/skill-evals.d.ts +8 -1
- package/package.json +1 -1
- package/skills/README.md +2 -0
- package/skills/pixerate-brushes/SKILL.md +106 -0
- package/skills/pixerate-brushes-design/SKILL.md +88 -0
- package/skills/pixerate-brushes-design/evals/canvas-chalk.json +15 -0
- package/skills/pixerate-brushes-design/evals/pink-highlighter.json +15 -0
- package/skills/pixerate-brushes-design/evals/port-to-vector.json +17 -0
- package/skills/pixerate-paint-editor/SKILL.md +26 -24
- package/skills/pixerate-paint-editor/references/brush-facets.md +30 -0
- package/skills/pixerate-paint-editor/references/gradient-paint.md +1 -1
- package/skills/pixerate-paint-editor/references/light-paint.md +2 -2
- package/skills/pixerate-paint-editor/references/oils.md +1 -1
- package/skills/pixerate-paint-editor/references/particle-brushes.md +8 -5
- package/skills/pixerate-paint-oil-impasto/SKILL.md +1 -1
- package/skills/pixerate-stickers/SKILL.md +1 -1
- package/skills/pixerate-video-editor/SKILL.md +1 -1
package/dist/brushes/index.cjs
CHANGED
|
@@ -11,19 +11,55 @@
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
var _chunkHS6QDWDFcjs = require('../chunk-HS6QDWDF.cjs');
|
|
15
14
|
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
|
|
19
|
-
var _chunkJSDND7DFcjs = require('../chunk-JSDND7DF.cjs');
|
|
20
|
-
require('../chunk-U67EN7GG.cjs');
|
|
21
18
|
|
|
22
19
|
|
|
23
|
-
var _chunkWOFXZ3XUcjs = require('../chunk-WOFXZ3XU.cjs');
|
|
24
20
|
|
|
25
21
|
|
|
26
22
|
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
var _chunk34KLWUH4cjs = require('../chunk-34KLWUH4.cjs');
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
var _chunkHS6QDWDFcjs = require('../chunk-HS6QDWDF.cjs');
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
var _chunkJSDND7DFcjs = require('../chunk-JSDND7DF.cjs');
|
|
60
|
+
require('../chunk-U67EN7GG.cjs');
|
|
61
|
+
require('../chunk-WOFXZ3XU.cjs');
|
|
62
|
+
|
|
27
63
|
|
|
28
64
|
var _chunkFQPUF2W2cjs = require('../chunk-FQPUF2W2.cjs');
|
|
29
65
|
require('../chunk-3K6HWEXZ.cjs');
|
|
@@ -32,1358 +68,199 @@ require('../chunk-3K6HWEXZ.cjs');
|
|
|
32
68
|
var _chunk2VX55NFMcjs = require('../chunk-2VX55NFM.cjs');
|
|
33
69
|
require('../chunk-474IQG74.cjs');
|
|
34
70
|
|
|
35
|
-
// src/brushes/
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var
|
|
40
|
-
var
|
|
41
|
-
var
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
var
|
|
45
|
-
var
|
|
46
|
-
var
|
|
47
|
-
var
|
|
48
|
-
var
|
|
49
|
-
var
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
pattern: BRUSH_STAMP_PATTERN,
|
|
63
|
-
description: `A sticker ref provider:id (find_stickers lists them; the editor's own are ${_chunkJSDND7DFcjs.STAMP_KINDS.map((k) => `editor:${k}`).join(", ")}). A bare editor stamp (star) means editor:star.`
|
|
64
|
-
};
|
|
65
|
-
var BRISTLES = object("Bristle tips: the tuft. Missing fields take their defaults.", {
|
|
66
|
-
count: int(3, 128, "Bristles in the tuft (default 32)."),
|
|
67
|
-
stiffness: unit("Stiff bristles follow the tip; soft ones lag and bend into curves at turns (default 0.5)."),
|
|
68
|
-
splay: unit("How far pressure spreads the tuft (default 0.5)."),
|
|
69
|
-
thickness: unit("Each bristle's line width as a fraction of the tip size (default 0.06)."),
|
|
70
|
-
load: unit("Paint per bristle: 1 never runs dry; lower, bristles run out along the stroke, a dry brush (default 0.6)."),
|
|
71
|
-
jitter: unit("Random variation between bristles: length, paint, position (default 0.4).")
|
|
72
|
-
});
|
|
73
|
-
var TIP = object(
|
|
74
|
-
"The tip: its shape and the dab it lays.",
|
|
75
|
-
{
|
|
76
|
-
shape: oneOf(BRUSH_TIP_SHAPES, "round, flat, chisel: an ellipse set by roundness and angle (the name is for people); bristle: a tuft of bristles (see bristle); stamp: textured stamps (see stamps), laid as objects or particles."),
|
|
77
|
-
size: num(1, _chunkFQPUF2W2cjs.MAX_BRUSH_SIZE, "Diameter in px (default 20)."),
|
|
78
|
-
hardness: unit("Edge hardness, 0 soft .. 1 hard (default 1)."),
|
|
79
|
-
spacing: num(0.01, 10, "Dab spacing as a fraction of the diameter: 0.05 smooth, 1 dotted (default 0.1)."),
|
|
80
|
-
angle: num(-360, 360, "Tip angle in degrees, counter-clockwise; added to the stroke direction or barrel with dynamics.rotation (default 0)."),
|
|
81
|
-
roundness: num(0.01, 1, "Roundness: 1 round (default), lower a flat ellipse (pastel, chisel)."),
|
|
82
|
-
opacity: unit("Stroke opacity ceiling: overlapping dabs never exceed it (default 1)."),
|
|
83
|
-
flow: unit("Build-up per dab towards the opacity: low flow builds softly, like an airbrush (default 1)."),
|
|
84
|
-
blend: oneOf(
|
|
85
|
-
_chunk2VX55NFMcjs.BLEND_MODES.map((m) => m.id),
|
|
86
|
-
"How the stroke paints onto the layer (default normal). pigment mixes like real paint; multiply darkens like marker ink; watercolor glazes; tint, highlight and shadow recolour, light and shade."
|
|
87
|
-
),
|
|
88
|
-
bristle: BRISTLES,
|
|
89
|
-
stamps: {
|
|
90
|
-
type: "array",
|
|
91
|
-
minItems: 1,
|
|
92
|
-
maxItems: _chunkHS6QDWDFcjs.MAX_STICKER_STAMPS,
|
|
93
|
-
items: STAMP,
|
|
94
|
-
description: `Stamp tips: the stickers. Objects take any sticker and pick one at random per mark (default editor:star; repeats count once); particles take only the editor's stamps, use the first ${_chunkHS6QDWDFcjs.MAX_DOT_TEXTURES} in marks.stampOrder, and repeats weight the order.`
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
["shape"]
|
|
98
|
-
);
|
|
99
|
-
var CONTINUOUS = object("Dabs laid along the path (the default).", { kind: { type: "string", const: "continuous", description: 'Always "continuous".' } }, ["kind"]);
|
|
100
|
-
var PARTICLES = object(
|
|
101
|
-
"Particles that move with the pen and draw as they go. Missing fields take their defaults.",
|
|
102
|
-
{
|
|
103
|
-
kind: { type: "string", const: "particles", description: 'Always "particles".' },
|
|
104
|
-
physics: oneOf(
|
|
105
|
-
_chunkHS6QDWDFcjs.PARTICLE_KINDS,
|
|
106
|
-
"How the particles move (default spring). string: strands dragged behind the pen (hair, fur); spring: on springs to the pen, overshooting; orbit: circling the pen (curls); flow: thrown into a swirling flow until they fade; elastic: links that stretch and snap back; fuzzy: winding strings waving out of step."
|
|
107
|
-
),
|
|
108
|
-
render: oneOf(_chunkHS6QDWDFcjs.PARTICLE_RENDERS, "How they draw (default line). dot: a mark per step; line: a continuous line each; sequence: beads spaced along each path; ribbon: the band between neighbouring paths filled."),
|
|
109
|
-
count: int(1, 64, "Particles (flow: thrown per tip of travel). Default 12."),
|
|
110
|
-
size: unit("Mark size as a fraction of the tip size; ribbon: its edge width (default 0.08)."),
|
|
111
|
-
spread: unit("How far apart they start, as a fraction of the tip size; ribbon: its width (default 0.5)."),
|
|
112
|
-
stiffness: unit("Spring, string and elastic stiffness: stiff follows closely, soft swings wide (default 0.4)."),
|
|
113
|
-
damping: unit("How quickly motion dies down (default 0.25)."),
|
|
114
|
-
speed: unit("Orbit and flow speed (default 0.5)."),
|
|
115
|
-
gravity: num(-1, 1, "Pull downwards; negative pulls up (default 0)."),
|
|
116
|
-
life: unit("Flow particles: how long they live (default 0.5)."),
|
|
117
|
-
interval: unit("Sequence: spacing of the beads (default 0.3)."),
|
|
118
|
-
ribbonFill: unit("Ribbon: fill opacity between the paths, relative to their edges (default 0.5; 0 only edges)."),
|
|
119
|
-
ribbonPairs: oneOf(_chunkHS6QDWDFcjs.RIBBON_PAIRS, "Ribbon: adjacent (default) joins each particle to its neighbour; first-last makes one band between the outermost two."),
|
|
120
|
-
waveAmplitude: unit("Wave: sideways swing as a fraction of the tip size (default 0: no wave)."),
|
|
121
|
-
waveLength: num(4, 2e3, "Wave: wavelength in px of pen travel (default 60)."),
|
|
122
|
-
wavePhaseJitter: unit("Wave: how far out of step the particles' waves are; 0 in step, 1 random phases (default 0)."),
|
|
123
|
-
stampOrder: oneOf(_chunkHS6QDWDFcjs.DOT_TEXTURE_ORDERS, "Stamp tips: sequence (default) uses the stamps in turn; random picks one per dot, seeded."),
|
|
124
|
-
stampRotation: oneOf(_chunkHS6QDWDFcjs.DOT_ROTATIONS, "Stamp tips: follow turns each with its particle's motion; random (default); fixed uses the tip angle.")
|
|
125
|
-
},
|
|
126
|
-
["kind"]
|
|
127
|
-
);
|
|
128
|
-
var OBJECTS = object(
|
|
129
|
-
"Each mark stays an editable object (a sticker) on a sticker layer; needs a stamp tip. Missing fields take their defaults.",
|
|
130
|
-
{
|
|
131
|
-
kind: { type: "string", const: "objects", description: 'Always "objects".' },
|
|
132
|
-
density: unit("About density \xD7 4 marks per tip diameter of travel; 0.25 \u2248 one per diameter (default 0.4)."),
|
|
133
|
-
sizeJitter: unit("Random size change (default 0.4)."),
|
|
134
|
-
rotationJitter: unit("Random turn as a fraction of \xB1180\xB0 (default 1)."),
|
|
135
|
-
scatter: num(0, 2, "How far from the path marks land, in tip diameters (default 0.5)."),
|
|
136
|
-
colourJitter: unit("Random colour change: at 1 up to \xB140\xB0 of hue and \xB10.15 OKLab lightness (default 0.2).")
|
|
137
|
-
},
|
|
138
|
-
["kind"]
|
|
139
|
-
);
|
|
140
|
-
var DYNAMICS = object("Pen feel: pressure, tilt, velocity, jitter, rotation and smoothing. Every amount 0 (off) .. 1 unless noted; missing fields take their defaults.", {
|
|
141
|
-
pressureSize: bool("Pressure scales the size, down to minSize (default true)."),
|
|
142
|
-
pressureOpacity: bool("Pressure scales the opacity (default false)."),
|
|
143
|
-
smoothing: num(0, 0.95, "Position smoothing of the input (default 0)."),
|
|
144
|
-
pressureSmoothing: num(0, 0.95, "Pressure smoothing, separate from position smoothing (default 0)."),
|
|
145
|
-
rotation: oneOf(_chunkHS6QDWDFcjs.BRUSH_ROTATIONS, "What turns the tip: fixed (tip.angle, default), stroke (direction of travel) or barrel (pen barrel rotation)."),
|
|
146
|
-
minSize: unit("Size at zero pressure as a fraction of the full size, with pressureSize (default 0)."),
|
|
147
|
-
pressureFlow: unit("How much pressure scales flow (default 0)."),
|
|
148
|
-
tiltSize: unit("Laying the pen down widens the tip, up to 2.5\xD7 (default 0)."),
|
|
149
|
-
tiltRoundness: unit("Laying the pen down flattens the tip along the tilt, side-of-the-pencil shading (default 0)."),
|
|
150
|
-
tiltOpacity: unit("Laying the pen down lightens the mark (default 0)."),
|
|
151
|
-
velocitySize: num(-1, 1, "Positive grows the tip on fast strokes, negative thins it; needs timed points (default 0)."),
|
|
152
|
-
velocityOpacity: num(-1, 1, "Positive darkens fast marks, negative lightens them; needs timed points (default 0)."),
|
|
153
|
-
sizeJitter: unit("Random size change per dab (default 0)."),
|
|
154
|
-
angleJitter: unit("Random angle per dab, as a fraction of \xB1180\xB0 (default 0)."),
|
|
155
|
-
opacityJitter: unit("Random opacity drop per dab (default 0)."),
|
|
156
|
-
scatter: num(0, 4, "Random offset across the stroke, in diameters (default 0).")
|
|
157
|
-
});
|
|
158
|
-
var EXCHANGE = object("Paint exchange with the canvas: picking up paint and mixing it into what the brush lays. Paint brushes on a dry, wet or thick surface and Mixer Brushes.", {
|
|
159
|
-
pickup: unit("Pick-up ratio: how much of the paint under each dab the brush lifts and carries (default 0; with a reservoir 0.5)."),
|
|
160
|
-
mix: unit("Mix ratio: how much of the carried paint goes into what the brush lays, against its own colour (default 0.5)."),
|
|
161
|
-
dirty: bool("Keep the carried paint after the stroke, so the next one starts with the last colour touched (default false)."),
|
|
162
|
-
reservoir: object("A paint reservoir makes this a Mixer Brush (an empty object takes every default).", {
|
|
163
|
-
load: unit("How much paint the reservoir holds; below 1 it drains per dab and long strokes run dry (default 0.5)."),
|
|
164
|
-
refill: bool("Refill with the paint colour before each stroke (default true)."),
|
|
165
|
-
loadsColour: bool("Load the current colour at all (default true; false: it only moves paint already down).")
|
|
166
|
-
})
|
|
167
|
-
});
|
|
168
|
-
var WET = object("Wet surface (watercolour, gouache, wet oil) and the wet tools. Missing fields take their defaults.", {
|
|
169
|
-
medium: oneOf(_chunkHS6QDWDFcjs.WET_MEDIA, "The wet medium; a layer takes the medium's wet settings the first time it holds wet paint (default: the variety when it is watercolor, gouache or oil, else watercolor)."),
|
|
170
|
-
water: unit("Wetness: water laid, 0.2 a damp brush .. 1 dripping (default 0.5)."),
|
|
171
|
-
pigment: unit("Pigment concentration: 0 clear water .. 1 straight from the tube (default 0.5)."),
|
|
172
|
-
body: unit("Body: 0 transparent watercolour .. 1 opaque gouache (default 0)."),
|
|
173
|
-
rewet: unit("How much dried paint the water lifts again: 0 staining (default 0)."),
|
|
174
|
-
load: unit("Paint loading: 1 never runs out; lower, the brush runs dry along a long stroke (default 1)."),
|
|
175
|
-
thinner: unit("Thinner (water or solvent): more transparent, runnier paint (default 0).")
|
|
176
|
-
});
|
|
177
|
-
var THICK = object("Thick surface (impasto: paint with relief, lit by the canvas lighting). Missing fields take their defaults.", {
|
|
178
|
-
applicator: oneOf(_chunkHS6QDWDFcjs.IMPASTO_TOOLS, "What lays the paint (default brush). brush: bristle ridges; tube: blobs squeezed from the tube; knife: scrapes the relief flat and smears; roller: a flat stippled band; gloop: a thick glossy bead."),
|
|
179
|
-
thickness: unit("How far the paint stands up (default 0.6)."),
|
|
180
|
-
gloss: unit("Shine: 0 matte .. 1 wet-looking gloss (default 0.4)."),
|
|
181
|
-
metallic: unit("Metallic: highlights take the paint colour, gold, copper, silver (default 0)."),
|
|
182
|
-
load: unit("Paint loading: 1 never runs out; lower, the stroke thins as the brush empties (default 0.9)."),
|
|
183
|
-
thinner: unit("Thinner: flatter, more transparent paint (default 0)."),
|
|
184
|
-
drag: unit("Knife and brush: how much of the paint under the tool is dragged along (default 0.4)."),
|
|
185
|
-
rim: unit("Light paint: light is stronger where the bead turns away, as on backlit glass (default 0)."),
|
|
186
|
-
clarity: unit("Glassy paint: the middle of a bead lets the layers below show through (default 0).")
|
|
187
|
-
});
|
|
188
|
-
var BEHAVIOUR = object("What the material does on the surface, and how tools work. Missing fields take their defaults.", {
|
|
189
|
-
surface: oneOf(BRUSH_SURFACES, "dry (default): stays where it lands; wet: flows, pools and dries (see wet); thick: stands up in relief (see thick)."),
|
|
190
|
-
grain: unit("Paper grain response: 0 ignores the grain, 1 catches only its peaks at light pressure (pencil, pastel, charcoal). Default 0."),
|
|
191
|
-
mixing: MIXING,
|
|
192
|
-
exchange: EXCHANGE,
|
|
193
|
-
wet: WET,
|
|
194
|
-
thick: THICK,
|
|
195
|
-
strength: unit("Tools: how strongly the blender, smudge or wet tool works per dab (default 0.5; smudge 0.7)."),
|
|
196
|
-
distance: unit("Blender: how far away colours are mixed in, as a fraction of the tip diameter (default 0.35)."),
|
|
197
|
-
length: unit("Smudge: how far paint is dragged, the share of carried paint kept per dab (default 0.85).")
|
|
198
|
-
});
|
|
199
|
-
var LIGHT = object("Light the brush gives off with its colour (glow and spill). Give light brushes dark paper.", {
|
|
200
|
-
amount: unit("Light per dab, scaled by its coverage and flow (default 0: none)."),
|
|
201
|
-
pressure: bool("Pressure scales the light (default false)."),
|
|
202
|
-
spill: object("Suggested spill for the layer, applied when it has none of its own.", {
|
|
203
|
-
radius: num(0, 512, "How far the light reaches, px; 0 turns spill off (a highlighter)."),
|
|
204
|
-
strength: num(0, 2, "How strong the spill is.")
|
|
205
|
-
}),
|
|
206
|
-
glow: bool("Suggest a glow layer effect for the layer (glow stays a layer effect).")
|
|
207
|
-
});
|
|
208
|
-
var MOTION = object("Animation after painting.", {
|
|
209
|
-
live: bool("Effect paint keeps playing on stroke layers (default false)."),
|
|
210
|
-
fps: int(1, 60, "Suggested playback rate in frames per second."),
|
|
211
|
-
waveSpeed: unit("Particle waves: how fast they run by stroke time; 0 they stand still (default 0), 1 about four a second.")
|
|
212
|
-
});
|
|
213
|
-
var SOLID = {
|
|
214
|
-
type: "string",
|
|
215
|
-
pattern: "^(#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})|rgba?\\(\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*,\\s*\\d{1,3}\\s*(,\\s*(0|1|0?\\.\\d+)\\s*)?\\))$",
|
|
216
|
-
description: "A solid colour: #rrggbb, #rrggbbaa or rgba(r, g, b, a)."
|
|
217
|
-
};
|
|
218
|
-
var DUAL = object("A colour for each colour scheme; the host picks one when the stroke starts and records it.", { light: SOLID, dark: SOLID }, ["light", "dark"]);
|
|
219
|
-
var EFFECT = object(
|
|
220
|
-
"Effect paint: the brush paints an effect (search_effects).",
|
|
221
|
-
{
|
|
222
|
-
type: { type: "string", const: "effect", description: 'Always "effect".' },
|
|
223
|
-
effect: { type: "string", minLength: 1, description: "The effect id." },
|
|
224
|
-
provider: { type: "string", description: "The provider's id when it was chosen." },
|
|
225
|
-
values: { type: "object", description: "Every control value (number, string, boolean or a number list)." },
|
|
226
|
-
time: { type: "number", minimum: 0, description: "Which moment of an animated effect, ms." },
|
|
227
|
-
map: object(
|
|
228
|
-
"Lay the effect along each stroke instead of fixing it to the canvas.",
|
|
229
|
-
{
|
|
230
|
-
by: { type: "string", const: "stroke", description: 'Always "stroke".' },
|
|
231
|
-
length: num(16, 4096, "Strip length: px of stroke per repeat of the effect."),
|
|
232
|
-
repeat: oneOf(["repeat", "mirror", "clamp"], "Past the strip end: start again, run back or hold.")
|
|
233
|
-
},
|
|
234
|
-
["by", "length", "repeat"]
|
|
235
|
-
),
|
|
236
|
-
live: bool("On a stroke layer the stroke keeps playing the effect.")
|
|
237
|
-
},
|
|
238
|
-
["type", "effect", "provider", "values", "time"]
|
|
239
|
-
);
|
|
240
|
-
var PAINT = {
|
|
241
|
-
description: "A colour a brush can carry: a solid colour, a light / dark pair, a gradient or effect paint.",
|
|
242
|
-
anyOf: [SOLID, DUAL, _chunkFQPUF2W2cjs.PAINT_GRADIENT_JSON_SCHEMA, EFFECT]
|
|
243
|
-
};
|
|
244
|
-
var COLOUR = object("The brush's colours. The user's colour still wins unless own is set.", {
|
|
245
|
-
default: {
|
|
246
|
-
...PAINT,
|
|
247
|
-
description: "The colour the brush starts with. A gradient is always painted (its paint / secondary stops take the user's colours); a solid colour or effect paint is suggested to the host."
|
|
248
|
-
},
|
|
249
|
-
palette: { type: "array", maxItems: MAX_BRUSH_PALETTE, items: PAINT, description: `Up to ${MAX_BRUSH_PALETTE} suggested colours.` },
|
|
250
|
-
own: bool("The brush always paints its own colour (a rainbow marker); default false.")
|
|
251
|
-
});
|
|
252
|
-
var BRUSH_JSON_SCHEMA = object(
|
|
253
|
-
"A brush made of facets. Only id, name, kind and tip.shape are required; every other field takes the default for its engine.",
|
|
254
|
-
{
|
|
255
|
-
id: { type: "string", pattern: _chunkHS6QDWDFcjs.BRUSH_ID.source, description: "Library id: lowercase letters, digits and dashes, up to 64 characters." },
|
|
256
|
-
name: { type: "string", minLength: 1, maxLength: 80, description: "Display name." },
|
|
257
|
-
description: { type: "string", maxLength: 500, description: "What the brush is for, in a sentence." },
|
|
258
|
-
tags: { type: "array", maxItems: 16, uniqueItems: true, items: { type: "string", pattern: BRUSH_WORD.source, description: "A tag: lowercase letters, digits and dashes." }, description: "Search tags." },
|
|
259
|
-
kind: oneOf(BRUSH_KINDS, "mark: lays a material (see medium); tool: works on paint already down (see tool)."),
|
|
260
|
-
medium: oneOf(BRUSH_MEDIA, "Marks: what it lays. paint (dry, wet or thick), ink, dry (pencil, pastel, charcoal) or spray (airbrush). Descriptive: the tip, marks and behaviour decide how it renders."),
|
|
261
|
-
variety: { type: "string", pattern: BRUSH_WORD.source, description: "What kind of the medium: oil, watercolor, gouache, pencil, pastel, charcoal, airbrush, marker, highlighter\u2026 A wet brush whose variety is watercolor, gouache or oil paints that medium." },
|
|
262
|
-
tool: oneOf(
|
|
263
|
-
BRUSH_TOOLS,
|
|
264
|
-
"Tools: eraser removes paint; blender mixes the colours under the tip; smudge drags paint along; water lays clear water (lifts dried paint with behaviour.wet.rewet); dryer dries wet paint; blow pushes water along; blot takes wet paint up; wet-blend evens out wet pigment; wet-drag drags wet paint."
|
|
265
|
-
),
|
|
266
|
-
tip: TIP,
|
|
267
|
-
marks: { description: "How the tip is laid along the path (default continuous).", oneOf: [CONTINUOUS, PARTICLES, OBJECTS] },
|
|
268
|
-
dynamics: DYNAMICS,
|
|
269
|
-
behaviour: BEHAVIOUR,
|
|
270
|
-
light: LIGHT,
|
|
271
|
-
motion: MOTION,
|
|
272
|
-
colour: COLOUR
|
|
273
|
-
},
|
|
274
|
-
["id", "name", "kind", "tip"]
|
|
275
|
-
);
|
|
276
|
-
var BRUSH_FACET_SCHEMAS = {
|
|
277
|
-
tip: TIP,
|
|
278
|
-
marks: { continuous: CONTINUOUS, particles: PARTICLES, objects: OBJECTS },
|
|
279
|
-
dynamics: DYNAMICS,
|
|
280
|
-
behaviour: BEHAVIOUR,
|
|
281
|
-
light: LIGHT,
|
|
282
|
-
motion: MOTION,
|
|
283
|
-
colour: COLOUR,
|
|
284
|
-
paint: PAINT
|
|
71
|
+
// src/brushes/ui.ts
|
|
72
|
+
var title = (s) => s.charAt(0).toUpperCase() + s.slice(1).replace(/-/g, " ");
|
|
73
|
+
var options = (values, labels = {}) => values.map((value) => ({ value, label: _nullishCoalesce(labels[value], () => ( title(value))) }));
|
|
74
|
+
var MEDIUM_LABELS = { paint: "Paint", ink: "Ink", dry: "Dry media", spray: "Spray" };
|
|
75
|
+
var TOOL_LABELS = { eraser: "Eraser", blender: "Blender", smudge: "Smudge", water: "Add water", dryer: "Dry", blow: "Blow", blot: "Blot", "wet-blend": "Wet blend", "wet-drag": "Wet smudge" };
|
|
76
|
+
var SHAPE_LABELS = { round: "Round", flat: "Flat", chisel: "Chisel", bristle: "Bristle", stamp: "Stamp" };
|
|
77
|
+
var MARKS_LABELS = { continuous: "Continuous", particles: "Particles", objects: "Stickers" };
|
|
78
|
+
var SURFACE_LABELS = { dry: "Dry", wet: "Wet (flows)", thick: "Thick (impasto)" };
|
|
79
|
+
var ROTATION_LABELS = { fixed: "Fixed", stroke: "Follow stroke", barrel: "Pen barrel" };
|
|
80
|
+
var PHYSICS_LABELS = { string: "Strings", spring: "Springs", orbit: "Orbits", flow: "Flow", elastic: "Elastic", fuzzy: "Fuzzy" };
|
|
81
|
+
var RENDER_LABELS = { dot: "Dots", line: "Lines", sequence: "Beads", ribbon: "Ribbon" };
|
|
82
|
+
var APPLICATOR_LABELS = { brush: "Brush", tube: "Paint tube", knife: "Palette knife", roller: "Roller", gloop: "Gloop pen" };
|
|
83
|
+
var WET_MEDIUM_LABELS = { watercolor: "Watercolour", gouache: "Gouache", oil: "Oil" };
|
|
84
|
+
var STAMP_OPTIONS = _chunkJSDND7DFcjs.STAMP_KINDS.map((k) => ({ value: `editor:${k}`, label: title(k) }));
|
|
85
|
+
var ARIA = {
|
|
86
|
+
"dynamics.rotation": "Brush rotation",
|
|
87
|
+
"tip.blend": "Brush blend",
|
|
88
|
+
"behaviour.mixing": "Brush mixing",
|
|
89
|
+
"behaviour.exchange.dirty": "Dirty brush",
|
|
90
|
+
"marks.physics": "Particle kind",
|
|
91
|
+
"marks.render": "Particle render",
|
|
92
|
+
"marks.ribbonPairs": "Ribbon pairs",
|
|
93
|
+
"marks.stampOrder": "Dot texture order",
|
|
94
|
+
"marks.stampRotation": "Dot rotation",
|
|
95
|
+
"behaviour.wet.medium": "Wet medium",
|
|
96
|
+
"behaviour.thick.applicator": "Impasto tool",
|
|
97
|
+
"light.pressure": "Light follows pressure"
|
|
285
98
|
};
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (
|
|
295
|
-
|
|
296
|
-
return void 0;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
99
|
+
var aria = (path, label) => _nullishCoalesce(ARIA[path], () => ( `Brush ${label.toLowerCase()}`));
|
|
100
|
+
function brushEditorSections(brush, profile = _chunk34KLWUH4cjs.PAINT_PROFILE) {
|
|
101
|
+
const resolved = _chunk34KLWUH4cjs.resolveBrush.call(void 0, brush);
|
|
102
|
+
const engine = _chunk34KLWUH4cjs.resolveEngine.call(void 0, brush);
|
|
103
|
+
const fieldOf = (facet) => _chunk34KLWUH4cjs.BRUSH_FIELDS.find((f) => f.facet === facet && f.engines.includes(engine));
|
|
104
|
+
const facetOf = (enginePath) => _optionalChain([(_nullishCoalesce(_chunk34KLWUH4cjs.BRUSH_FIELDS.find((f) => f.engine === enginePath && f.engines.includes(engine)), () => ( _chunk34KLWUH4cjs.BRUSH_FIELDS.find((f) => f.engine === enginePath)))), 'optionalAccess', _ => _.facet]);
|
|
105
|
+
const value = (path) => {
|
|
106
|
+
const own = _chunk34KLWUH4cjs.getPath.call(void 0, brush, path);
|
|
107
|
+
if (own !== void 0) return own;
|
|
108
|
+
const field = fieldOf(path);
|
|
109
|
+
if (!field) return void 0;
|
|
110
|
+
const v = _chunk34KLWUH4cjs.getPath.call(void 0, resolved, field.engine);
|
|
111
|
+
return field.map ? field.map.toFacet(v) : v;
|
|
112
|
+
};
|
|
113
|
+
const warned = new Map(_chunk34KLWUH4cjs.checkBrush.call(void 0, brush, profile).issues.filter((i) => i.severity === "warning").map((i) => [i.facet, i.reason]));
|
|
114
|
+
const noteFor = (path) => _optionalChain([[...warned], 'access', _2 => _2.find, 'call', _3 => _3(([facet]) => path === facet || path.startsWith(`${facet}.`)), 'optionalAccess', _4 => _4[1]]);
|
|
115
|
+
const withNote = (c) => {
|
|
116
|
+
const note = noteFor(c.path);
|
|
117
|
+
return note ? { ...c, note } : c;
|
|
118
|
+
};
|
|
119
|
+
const slider = (c, path = facetOf(c.path)) => {
|
|
120
|
+
if (!path) return null;
|
|
121
|
+
const v = value(path);
|
|
122
|
+
return withNote({ kind: "slider", path, label: c.label, ariaLabel: aria(path, c.label), min: c.min, max: path === "tip.size" ? Math.min(c.max, _chunkFQPUF2W2cjs.MAX_BRUSH_SIZE) : c.max, step: c.step, value: typeof v === "number" ? v : c.min });
|
|
123
|
+
};
|
|
124
|
+
const choice = (path, label, opts, fallback = _nullishCoalesce(_optionalChain([opts, 'access', _5 => _5[0], 'optionalAccess', _6 => _6.value]), () => ( ""))) => withNote({ kind: "choice", path, label, ariaLabel: aria(path, label), options: opts, value: String(_nullishCoalesce(value(path), () => ( fallback))) });
|
|
125
|
+
const toggle = (path, label) => withNote({ kind: "toggle", path, label, ariaLabel: aria(path, label), value: Boolean(value(path)) });
|
|
126
|
+
const present = (cs) => cs.filter((c) => Boolean(c));
|
|
127
|
+
const sections = [];
|
|
128
|
+
const add = (id, name, controls) => {
|
|
129
|
+
const list = present(controls);
|
|
130
|
+
if (list.length) sections.push({ id, title: name, controls: list });
|
|
131
|
+
};
|
|
132
|
+
const isTool = brush.kind === "tool";
|
|
133
|
+
const shape = brush.tip.shape;
|
|
134
|
+
const marks = _nullishCoalesce(_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]), () => ( "continuous"));
|
|
135
|
+
add("medium", "Medium", [
|
|
136
|
+
profile.kinds.length > 1 && choice("kind", "Kind", options(profile.kinds, { mark: "Lays a material", tool: "Works on paint" })),
|
|
137
|
+
!isTool && choice("medium", "Medium", [{ value: "", label: "Any" }, ...options(_chunk34KLWUH4cjs.BRUSH_MEDIA, MEDIUM_LABELS)], ""),
|
|
138
|
+
!isTool && withNote({ kind: "text", path: "variety", label: "Variety", ariaLabel: "Brush variety", value: _nullishCoalesce(brush.variety, () => ( "")), placeholder: "pencil, oil, highlighter\u2026" }),
|
|
139
|
+
isTool && profile.tools.length > 0 && choice("tool", "Tool", options(profile.tools, TOOL_LABELS))
|
|
140
|
+
]);
|
|
141
|
+
const engineControls = _chunk34KLWUH4cjs.brushEngineControls.call(void 0, resolved);
|
|
142
|
+
const tipSliders = _chunk34KLWUH4cjs.BRUSH_SLIDERS.filter((c) => c.path.startsWith("tip.") && c.path !== "tip.smoothing");
|
|
143
|
+
add("shape", "Shape", [
|
|
144
|
+
choice("tip.shape", "Tip", options(profile.tipShapes.filter((s) => !isTool || s !== "stamp"), SHAPE_LABELS)),
|
|
145
|
+
...tipSliders.map((c) => slider(c)),
|
|
146
|
+
engine === "dab" && choice("tip.blend", "Blend", _chunk2VX55NFMcjs.BLEND_MODES.map((m) => ({ value: m.id, label: m.label })), "normal"),
|
|
147
|
+
...shape === "bristle" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("bristle.")).map((c) => slider(c)) : [],
|
|
148
|
+
shape === "stamp" && withNote({ kind: "stamps", path: "tip.stamps", label: "Stamps", ariaLabel: "Brush stamps", value: [..._nullishCoalesce(value("tip.stamps"), () => ( []))], max: marks === "particles" ? _chunkHS6QDWDFcjs.MAX_DOT_TEXTURES : _chunkHS6QDWDFcjs.MAX_STICKER_STAMPS, options: STAMP_OPTIONS })
|
|
149
|
+
]);
|
|
150
|
+
if (!isTool && profile.marks.length > 1) {
|
|
151
|
+
const particles = marks === "particles" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("particle.") && c.path !== "particle.waveSpeed") : [];
|
|
152
|
+
const objects = marks === "objects" && engineControls ? engineControls.sliders.filter((c) => c.path.startsWith("sticker.")) : [];
|
|
153
|
+
const render = value("marks.render");
|
|
154
|
+
add("marks", "Marks", [
|
|
155
|
+
choice("marks.kind", "Laid as", options(profile.marks, MARKS_LABELS), "continuous"),
|
|
156
|
+
marks === "particles" && choice("marks.physics", "Particles", options(_chunkHS6QDWDFcjs.PARTICLE_KINDS, PHYSICS_LABELS)),
|
|
157
|
+
marks === "particles" && choice("marks.render", "Drawn as", options(_chunkHS6QDWDFcjs.PARTICLE_RENDERS, RENDER_LABELS)),
|
|
158
|
+
marks === "particles" && render === "ribbon" && choice("marks.ribbonPairs", "Ribbon joins", options(_chunkHS6QDWDFcjs.RIBBON_PAIRS, { adjacent: "Neighbours", "first-last": "Outermost" })),
|
|
159
|
+
marks === "particles" && shape === "stamp" && choice("marks.stampOrder", "Texture order", options(_chunkHS6QDWDFcjs.DOT_TEXTURE_ORDERS, { sequence: "In turn", random: "Random" })),
|
|
160
|
+
marks === "particles" && shape === "stamp" && choice("marks.stampRotation", "Texture turn", options(_chunkHS6QDWDFcjs.DOT_ROTATIONS, { follow: "Follow motion", random: "Random", fixed: "Tip angle" })),
|
|
161
|
+
...particles.map((c) => slider(c)),
|
|
162
|
+
...objects.map((c) => slider(c))
|
|
163
|
+
]);
|
|
344
164
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
165
|
+
const feel = _chunk34KLWUH4cjs.BRUSH_SLIDERS.filter((c) => ["tip.smoothing", "pressureSmoothing", "dynamics.minSize", "dynamics.tiltSize", "dynamics.velocitySize"].includes(c.path)).filter((c) => !(c.path === "dynamics.tiltSize" && profile.tilt === "none") && !(c.path === "dynamics.velocitySize" && profile.velocity === "none"));
|
|
166
|
+
add("feel", "Feel", [
|
|
167
|
+
...feel.map((c) => slider(c)),
|
|
168
|
+
toggle("dynamics.pressureSize", "Pressure \u2192 size"),
|
|
169
|
+
toggle("dynamics.pressureOpacity", "Pressure \u2192 opacity"),
|
|
170
|
+
choice("dynamics.rotation", "Rotation", options(_chunkHS6QDWDFcjs.BRUSH_ROTATIONS, ROTATION_LABELS))
|
|
171
|
+
]);
|
|
172
|
+
const surfaces = profile.surfaces;
|
|
173
|
+
const engineSliders = (_nullishCoalesce(_optionalChain([engineControls, 'optionalAccess', _9 => _9.sliders]), () => ( []))).filter((c) => !/^(bristle|particle|sticker)\./.test(c.path) && c.path !== "light.amount" && c.path !== "impasto.rim" && c.path !== "impasto.clarity");
|
|
174
|
+
const exchangeOk = (path) => !_optionalChain([path, 'optionalAccess', _10 => _10.startsWith, 'call', _11 => _11("behaviour.exchange")]) || (path.startsWith("behaviour.exchange.reservoir") ? profile.reservoir !== "none" : profile.exchange !== "none");
|
|
175
|
+
add("behaviour", _nullishCoalesce(_optionalChain([engineControls, 'optionalAccess', _12 => _12.title]), () => ( "Behaviour")), [
|
|
176
|
+
!isTool && surfaces.length > 1 && choice("behaviour.surface", "Surface", options(surfaces, SURFACE_LABELS), "dry"),
|
|
177
|
+
profile.grain !== "none" && slider({ path: "grain", label: "Grain", min: 0, max: 1, step: 0.01 }, "behaviour.grain"),
|
|
178
|
+
engine === "wet" && !isTool && choice("behaviour.wet.medium", "Medium", options(_chunkHS6QDWDFcjs.WET_MEDIA, WET_MEDIUM_LABELS), "watercolor"),
|
|
179
|
+
engine === "impasto" && choice("behaviour.thick.applicator", "Tool", options(_chunkHS6QDWDFcjs.IMPASTO_TOOLS, APPLICATOR_LABELS), "brush"),
|
|
180
|
+
...engineSliders.map((c) => exchangeOk(facetOf(c.path)) ? slider(c) : null),
|
|
181
|
+
_optionalChain([engineControls, 'optionalAccess', _13 => _13.mixingPath]) && fieldOf("behaviour.mixing") && choice("behaviour.mixing", "Mixing", options(["pigment", "rgb"], { pigment: "Pigment", rgb: "RGB" })),
|
|
182
|
+
_optionalChain([engineControls, 'optionalAccess', _14 => _14.dirty]) && profile.exchange !== "none" && fieldOf("behaviour.exchange.dirty") && toggle("behaviour.exchange.dirty", "Dirty brush"),
|
|
183
|
+
engine === "mixer" && toggle("behaviour.exchange.reservoir.refill", "Load each stroke")
|
|
184
|
+
]);
|
|
185
|
+
if (!isTool && profile.light !== "none" && _optionalChain([engineControls, 'optionalAccess', _15 => _15.light])) {
|
|
186
|
+
add("light", "Light", [
|
|
187
|
+
slider({ path: "light.amount", label: "Light", min: 0, max: 1, step: 0.01 }),
|
|
188
|
+
toggle("light.pressure", "Light follows pressure"),
|
|
189
|
+
...engine === "impasto" ? [slider({ path: "impasto.rim", label: "Rim", min: 0, max: 1, step: 0.01 }), slider({ path: "impasto.clarity", label: "Clarity", min: 0, max: 1, step: 0.01 })] : [],
|
|
190
|
+
withNote({ kind: "slider", path: "light.spill.radius", label: "Spill", ariaLabel: "Brush light spill", min: 0, max: 128, step: 1, value: _nullishCoalesce(_optionalChain([brush, 'access', _16 => _16.light, 'optionalAccess', _17 => _17.spill, 'optionalAccess', _18 => _18.radius]), () => ( 24)) }),
|
|
191
|
+
toggle("light.glow", "Suggest a glow")
|
|
192
|
+
]);
|
|
350
193
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const r = read(v, child, `${path}.${key}`, problems);
|
|
360
|
-
if (r !== void 0) out[key] = r;
|
|
194
|
+
if (profile.motion !== "none" && marks === "particles") add("motion", "Motion", [slider({ path: "particle.waveSpeed", label: "Wave speed", min: 0, max: 1, step: 0.01 })]);
|
|
195
|
+
if (!isTool) {
|
|
196
|
+
const own = _optionalChain([brush, 'access', _19 => _19.colour, 'optionalAccess', _20 => _20.default]);
|
|
197
|
+
add("colour", "Colour", [
|
|
198
|
+
withNote({ kind: "colour", path: "colour.default", label: "Default colour", ariaLabel: "Brush default colour", value: typeof own === "string" && /^#[0-9a-f]{6}/i.test(own) ? own.slice(0, 7).toLowerCase() : null }),
|
|
199
|
+
withNote({ kind: "palette", path: "colour.palette", label: "Palette", ariaLabel: "Brush palette", value: (_nullishCoalesce(_optionalChain([brush, 'access', _21 => _21.colour, 'optionalAccess', _22 => _22.palette]), () => ( []))).filter((c) => typeof c === "string"), max: _chunk34KLWUH4cjs.MAX_BRUSH_PALETTE }),
|
|
200
|
+
toggle("colour.own", "Always its own colour")
|
|
201
|
+
]);
|
|
361
202
|
}
|
|
362
|
-
return
|
|
203
|
+
return sections;
|
|
363
204
|
}
|
|
364
|
-
function
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
205
|
+
function setBrushEditorValue(brush, path, value) {
|
|
206
|
+
const next = JSON.parse(JSON.stringify(brush));
|
|
207
|
+
if (path === "kind") {
|
|
208
|
+
if (value === "tool") {
|
|
209
|
+
delete next.medium;
|
|
210
|
+
delete next.variety;
|
|
211
|
+
delete next.marks;
|
|
212
|
+
delete next.light;
|
|
213
|
+
delete next.colour;
|
|
214
|
+
next.tool = _nullishCoalesce(next.tool, () => ( "eraser"));
|
|
215
|
+
if (next.tip.shape === "stamp") next.tip = { shape: "round", ...next.tip.size !== void 0 ? { size: next.tip.size } : {} };
|
|
216
|
+
} else delete next.tool;
|
|
217
|
+
next.kind = value;
|
|
218
|
+
} else if (path === "marks.kind") {
|
|
219
|
+
next.marks = value === "continuous" ? void 0 : { kind: value };
|
|
220
|
+
if (value !== "continuous" && next.tip.shape === "bristle") next.tip = { ...next.tip, shape: "round", bristle: void 0 };
|
|
221
|
+
if (value === "objects") next.tip = { ...next.tip, shape: "stamp" };
|
|
222
|
+
} else if (path === "tip.shape" && value !== "stamp") {
|
|
223
|
+
next.tip = { ...next.tip, shape: value, stamps: void 0 };
|
|
224
|
+
if (value !== "bristle") delete next.tip.bristle;
|
|
225
|
+
} else if (value === void 0 || value === "") {
|
|
226
|
+
const keys = path.split(".");
|
|
227
|
+
const parent = _chunk34KLWUH4cjs.getPath.call(void 0, next, keys.slice(0, -1).join("."));
|
|
228
|
+
if (keys.length === 1) delete next[keys[0]];
|
|
229
|
+
else if (parent) delete parent[keys[keys.length - 1]];
|
|
230
|
+
} else _chunk34KLWUH4cjs.setPath.call(void 0, next, path, value);
|
|
231
|
+
const problems = [];
|
|
232
|
+
try {
|
|
233
|
+
return { brush: _chunk34KLWUH4cjs.normalizeBrushSpec.call(void 0, JSON.parse(JSON.stringify(next)), problems), problems };
|
|
234
|
+
} catch (e) {
|
|
235
|
+
return { brush, problems: [e.message] };
|
|
374
236
|
}
|
|
375
|
-
problems.push(`${path} is not a colour (#rrggbb, #rrggbbaa, rgba(), { light, dark }, a gradient or effect paint); dropped.`);
|
|
376
|
-
return void 0;
|
|
377
237
|
}
|
|
378
|
-
function
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
else throw new Error(`Brush "${raw.id}" kind ${JSON.stringify(raw.kind)} is not valid: use mark (lays a material) or tool (works on paint already down).`);
|
|
389
|
-
if (kind === "tool" && !tool) throw new Error(`Brush "${raw.id}" is a tool and needs tool: one of ${BRUSH_TOOLS.join(", ")}.`);
|
|
390
|
-
const { colour: rawColour, marks: rawMarks, kind: _k, id: _i, name: _n, tool: _t, ...rest } = raw;
|
|
391
|
-
const out = readObject(rest, BRUSH_JSON_SCHEMA, "brush", problems);
|
|
392
|
-
const brush = { id: raw.id, name, ...out, kind, ...tool ? { tool } : {}, tip: _nullishCoalesce(out.tip, () => ( { shape: "round" })) };
|
|
393
|
-
const ordered = () => {
|
|
394
|
-
const { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, motion, colour } = brush;
|
|
395
|
-
const all = { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, motion, colour };
|
|
396
|
-
return Object.fromEntries(Object.entries(all).filter(([, v]) => v !== void 0));
|
|
397
|
-
};
|
|
398
|
-
if (!out.tip) problems.push("tip is missing; a round tip is used.");
|
|
399
|
-
if (!brush.tip.shape) {
|
|
400
|
-
problems.push("tip.shape is missing; round is used.");
|
|
401
|
-
brush.tip = { ...brush.tip, shape: "round" };
|
|
402
|
-
}
|
|
403
|
-
if (rawMarks !== void 0) {
|
|
404
|
-
const k = isObject(rawMarks) ? rawMarks.kind : void 0;
|
|
405
|
-
const schema = BRUSH_FACET_SCHEMAS.marks[k];
|
|
406
|
-
if (!schema) problems.push(`marks.kind ${JSON.stringify(k)} is not valid; use continuous, particles or objects. marks dropped.`);
|
|
407
|
-
else brush.marks = readObject(rawMarks, schema, "brush.marks", problems);
|
|
408
|
-
}
|
|
409
|
-
if (rawColour !== void 0) {
|
|
410
|
-
const c = readObject(rawColour, { ...BRUSH_FACET_SCHEMAS.colour, properties: { own: BRUSH_FACET_SCHEMAS.colour.properties.own, default: {}, palette: {} } }, "brush.colour", problems);
|
|
411
|
-
if (c) {
|
|
412
|
-
const colour = {};
|
|
413
|
-
if (c.default !== void 0) {
|
|
414
|
-
const p = readPaint(c.default, "brush.colour.default", problems);
|
|
415
|
-
if (p !== void 0) colour.default = p;
|
|
416
|
-
}
|
|
417
|
-
if (c.palette !== void 0) {
|
|
418
|
-
if (!Array.isArray(c.palette)) problems.push("brush.colour.palette must be a list; dropped.");
|
|
419
|
-
else {
|
|
420
|
-
const list = c.palette.map((p, i) => readPaint(p, `brush.colour.palette[${i}]`, problems)).filter((p) => p !== void 0);
|
|
421
|
-
if (list.length > MAX_BRUSH_PALETTE) problems.push(`brush.colour.palette has more than ${MAX_BRUSH_PALETTE} colours; the rest were dropped.`);
|
|
422
|
-
colour.palette = list.slice(0, MAX_BRUSH_PALETTE);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
if (typeof c.own === "boolean") colour.own = c.own;
|
|
426
|
-
brush.colour = colour;
|
|
238
|
+
function brushLibraryGroups(entries, filter = {}) {
|
|
239
|
+
const words = (s) => s.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter(Boolean);
|
|
240
|
+
const wanted = words(_nullishCoalesce(filter.text, () => ( "")));
|
|
241
|
+
const groups = /* @__PURE__ */ new Map();
|
|
242
|
+
for (const e of entries) {
|
|
243
|
+
const b = e.brush;
|
|
244
|
+
if (filter.source && filter.source === "builtin" !== e.builtin) continue;
|
|
245
|
+
if (wanted.length) {
|
|
246
|
+
const text = words([b.id, b.name, _nullishCoalesce(b.variety, () => ( "")), _nullishCoalesce(b.medium, () => ( "")), _nullishCoalesce(b.tool, () => ( "")), ..._nullishCoalesce(b.tags, () => ( []))].join(" "));
|
|
247
|
+
if (!wanted.every((w) => text.some((t) => t.startsWith(w)))) continue;
|
|
427
248
|
}
|
|
249
|
+
if (filter.profile && !_chunk34KLWUH4cjs.checkBrush.call(void 0, b, filter.profile).ok) continue;
|
|
250
|
+
const id = b.kind === "tool" ? "tools" : _nullishCoalesce(b.medium, () => ( "other"));
|
|
251
|
+
let g = groups.get(id);
|
|
252
|
+
if (!g) groups.set(id, g = { id, title: id === "tools" ? "Tools" : id === "other" ? "Other" : MEDIUM_LABELS[id], varieties: [] });
|
|
253
|
+
const variety = b.kind === "tool" ? "" : _nullishCoalesce(b.variety, () => ( ""));
|
|
254
|
+
let v = g.varieties.find((x) => x.variety === variety);
|
|
255
|
+
if (!v) g.varieties.push(v = { variety, title: variety ? title(variety) : "", entries: [] });
|
|
256
|
+
v.entries.push(e);
|
|
428
257
|
}
|
|
429
|
-
const
|
|
430
|
-
|
|
431
|
-
drop("tool", "a mark brush has no tool (set kind to tool)");
|
|
432
|
-
delete brush.tool;
|
|
433
|
-
}
|
|
434
|
-
if (kind === "tool") {
|
|
435
|
-
if (brush.medium) {
|
|
436
|
-
drop("medium", "tools lay no medium");
|
|
437
|
-
delete brush.medium;
|
|
438
|
-
}
|
|
439
|
-
if (brush.marks) {
|
|
440
|
-
drop("marks", "tools lay no marks");
|
|
441
|
-
delete brush.marks;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
if (_optionalChain([brush, 'access', _3 => _3.marks, 'optionalAccess', _4 => _4.kind]) === "objects" && brush.tip.shape !== "stamp") {
|
|
445
|
-
problems.push("marks objects lay stamps: tip.shape set to stamp.");
|
|
446
|
-
brush.tip.shape = "stamp";
|
|
447
|
-
}
|
|
448
|
-
if (brush.tip.bristle && brush.tip.shape !== "bristle") {
|
|
449
|
-
drop("tip.bristle", "only bristle tips have a tuft");
|
|
450
|
-
delete brush.tip.bristle;
|
|
451
|
-
}
|
|
452
|
-
if (brush.tip.stamps && brush.tip.shape !== "stamp") {
|
|
453
|
-
drop("tip.stamps", "only stamp tips lay stamps");
|
|
454
|
-
delete brush.tip.stamps;
|
|
455
|
-
}
|
|
456
|
-
if (brush.tip.stamps) {
|
|
457
|
-
const particles = _optionalChain([brush, 'access', _5 => _5.marks, 'optionalAccess', _6 => _6.kind]) === "particles";
|
|
458
|
-
const stamps = brush.tip.stamps.flatMap((s) => {
|
|
459
|
-
const ref = _chunkJSDND7DFcjs.normalizeStickerRef.call(void 0, s);
|
|
460
|
-
if (particles && !_chunkJSDND7DFcjs.editorStampOf.call(void 0, ref)) {
|
|
461
|
-
problems.push(`brush.tip.stamps "${ref}" dropped: particle marks lay only the editor's stamps (editor:star, editor:dot\u2026).`);
|
|
462
|
-
return [];
|
|
463
|
-
}
|
|
464
|
-
return [ref];
|
|
465
|
-
});
|
|
466
|
-
if (stamps.length) brush.tip.stamps = stamps;
|
|
467
|
-
else {
|
|
468
|
-
drop("tip.stamps", "none of the stamps can be laid");
|
|
469
|
-
delete brush.tip.stamps;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
const b = brush.behaviour;
|
|
473
|
-
if (b) {
|
|
474
|
-
const wetTool = kind === "tool" && WET_BRUSH_TOOLS.includes(brush.tool);
|
|
475
|
-
if (kind === "tool" && b.surface !== void 0) {
|
|
476
|
-
drop("behaviour.surface", "a tool works on the surface it finds");
|
|
477
|
-
delete b.surface;
|
|
478
|
-
}
|
|
479
|
-
if (b.wet && b.surface !== "wet" && !wetTool) {
|
|
480
|
-
drop("behaviour.wet", "it needs surface wet or a wet tool");
|
|
481
|
-
delete b.wet;
|
|
482
|
-
}
|
|
483
|
-
if (b.thick && b.surface !== "thick") {
|
|
484
|
-
drop("behaviour.thick", "it needs surface thick");
|
|
485
|
-
delete b.thick;
|
|
486
|
-
}
|
|
487
|
-
if (b.strength !== void 0 && !(kind === "tool" && brush.tool !== "eraser")) {
|
|
488
|
-
drop("behaviour.strength", "only the blender, smudge and wet tools have a strength");
|
|
489
|
-
delete b.strength;
|
|
490
|
-
}
|
|
491
|
-
if (b.distance !== void 0 && brush.tool !== "blender") {
|
|
492
|
-
drop("behaviour.distance", "only the blender has a blend distance");
|
|
493
|
-
delete b.distance;
|
|
494
|
-
}
|
|
495
|
-
if (b.length !== void 0 && brush.tool !== "smudge") {
|
|
496
|
-
drop("behaviour.length", "only the smudge tool has a drag length");
|
|
497
|
-
delete b.length;
|
|
498
|
-
}
|
|
499
|
-
if (b.exchange && kind === "tool" && !wetTool) {
|
|
500
|
-
drop("behaviour.exchange", `the ${brush.tool} does not pick paint up`);
|
|
501
|
-
delete b.exchange;
|
|
502
|
-
} else if (b.exchange && (_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]) === "particles" || _optionalChain([brush, 'access', _9 => _9.marks, 'optionalAccess', _10 => _10.kind]) === "objects" || brush.tip.shape === "bristle")) {
|
|
503
|
-
drop("behaviour.exchange", "particle, object and bristle marks do not pick paint up");
|
|
504
|
-
delete b.exchange;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
return ordered();
|
|
258
|
+
const order = ["dry", "ink", "paint", "spray", "other", "tools"];
|
|
259
|
+
return [...groups.values()].sort((a, b) => order.indexOf(a.id) - order.indexOf(b.id));
|
|
508
260
|
}
|
|
509
261
|
|
|
510
|
-
// src/brushes/resolve.ts
|
|
511
|
-
var ALL = ["dab", "eraser", "mixer", "blender", "smudge", "wet", "impasto", "particle", "bristle", "sticker"];
|
|
512
|
-
var EXCHANGE2 = ["dab", "wet", "impasto"];
|
|
513
|
-
var NOT = { toEngine: (v) => !v, toFacet: (v) => !v };
|
|
514
|
-
var EDITOR_STAMPS = {
|
|
515
|
-
toEngine: (v) => v.flatMap((ref) => {
|
|
516
|
-
try {
|
|
517
|
-
const stamp = _chunkJSDND7DFcjs.editorStampOf.call(void 0, ref);
|
|
518
|
-
return stamp ? [stamp] : [];
|
|
519
|
-
} catch (e) {
|
|
520
|
-
return [];
|
|
521
|
-
}
|
|
522
|
-
}),
|
|
523
|
-
toFacet: (v) => v.map((stamp) => `editor:${stamp}`)
|
|
524
|
-
};
|
|
525
|
-
var f = (facet, engine, engines = ALL, extra = {}) => ({ facet, engine, engines, ...extra });
|
|
526
|
-
var each = (facetPrefix, enginePrefix, keys, engines) => keys.map((k) => f(`${facetPrefix}.${k}`, `${enginePrefix}.${k}`, engines));
|
|
527
|
-
var BRUSH_FIELDS = [
|
|
528
|
-
...each("tip", "tip", ["size", "hardness", "spacing", "angle", "roundness", "opacity", "flow", "blend"]),
|
|
529
|
-
...each("dynamics", "tip", ["smoothing", "pressureSize", "pressureOpacity"]),
|
|
530
|
-
f("dynamics.pressureSmoothing", "pressureSmoothing"),
|
|
531
|
-
f("dynamics.rotation", "rotation"),
|
|
532
|
-
...each("dynamics", "dynamics", ["minSize", "pressureFlow", "tiltSize", "tiltRoundness", "tiltOpacity", "velocitySize", "velocityOpacity", "sizeJitter", "angleJitter", "opacityJitter", "scatter"]),
|
|
533
|
-
f("behaviour.grain", "grain"),
|
|
534
|
-
...each("light", "light", ["amount", "pressure"]),
|
|
535
|
-
// Paint exchange: the dab, wet and impasto engines' behaviour, or the Mixer Brush's settings.
|
|
536
|
-
f("behaviour.exchange.pickup", "behavior.pickup", EXCHANGE2),
|
|
537
|
-
f("behaviour.exchange.mix", "behavior.mix", EXCHANGE2),
|
|
538
|
-
f("behaviour.exchange.dirty", "behavior.dirty", EXCHANGE2),
|
|
539
|
-
f("behaviour.mixing", "behavior.mixing", EXCHANGE2),
|
|
540
|
-
f("behaviour.exchange.pickup", "mixer.wet", ["mixer"]),
|
|
541
|
-
f("behaviour.exchange.mix", "mixer.mix", ["mixer"]),
|
|
542
|
-
f("behaviour.exchange.dirty", "mixer.cleanEachStroke", ["mixer"], { map: NOT }),
|
|
543
|
-
f("behaviour.mixing", "mixer.mixing", ["mixer"]),
|
|
544
|
-
f("behaviour.exchange.reservoir.load", "mixer.load", ["mixer"]),
|
|
545
|
-
f("behaviour.exchange.reservoir.refill", "mixer.loadEachStroke", ["mixer"]),
|
|
546
|
-
f("behaviour.exchange.reservoir.loadsColour", "loadsColor", ["mixer"]),
|
|
547
|
-
// Tools.
|
|
548
|
-
f("behaviour.strength", "blender.strength", ["blender"]),
|
|
549
|
-
f("behaviour.distance", "blender.distance", ["blender"]),
|
|
550
|
-
f("behaviour.mixing", "blender.mixing", ["blender"]),
|
|
551
|
-
f("behaviour.strength", "smudge.strength", ["smudge"]),
|
|
552
|
-
f("behaviour.length", "smudge.length", ["smudge"]),
|
|
553
|
-
f("behaviour.mixing", "smudge.mixing", ["smudge"]),
|
|
554
|
-
f("behaviour.strength", "wet.strength", ["wet"]),
|
|
555
|
-
// Surfaces.
|
|
556
|
-
...each("behaviour.wet", "wet", ["medium", "water", "pigment", "body", "rewet", "load", "thinner"], ["wet"]),
|
|
557
|
-
f("behaviour.thick.applicator", "impasto.tool", ["impasto"]),
|
|
558
|
-
...each("behaviour.thick", "impasto", ["thickness", "gloss", "metallic", "load", "thinner", "drag", "rim", "clarity"], ["impasto"]),
|
|
559
|
-
// Marks.
|
|
560
|
-
f("marks.physics", "particle.kind", ["particle"]),
|
|
561
|
-
...each("marks", "particle", ["render", "count", "size", "spread", "stiffness", "damping", "speed", "gravity", "life", "interval", "ribbonFill", "ribbonPairs", "waveAmplitude", "waveLength", "wavePhaseJitter"], ["particle"]),
|
|
562
|
-
f("marks.stampOrder", "particle.dotTextureOrder", ["particle"]),
|
|
563
|
-
f("marks.stampRotation", "particle.dotRotation", ["particle"]),
|
|
564
|
-
f("tip.stamps", "particle.dotTextures", ["particle"], { shapes: ["stamp"], map: EDITOR_STAMPS }),
|
|
565
|
-
f("motion.waveSpeed", "particle.waveSpeed", ["particle"]),
|
|
566
|
-
f("tip.stamps", "sticker.stamps", ["sticker"], { shapes: ["stamp"] }),
|
|
567
|
-
...each("marks", "sticker", ["density", "sizeJitter", "rotationJitter", "scatter"], ["sticker"]),
|
|
568
|
-
f("marks.colourJitter", "sticker.colorJitter", ["sticker"]),
|
|
569
|
-
...each("tip.bristle", "bristle", ["count", "stiffness", "splay", "thickness", "load", "jitter"], ["bristle"])
|
|
570
|
-
];
|
|
571
|
-
var WET_TOOL_OF = { water: "water", dryer: "dry", blow: "blow", blot: "blot", "wet-blend": "blend", "wet-drag": "smudge" };
|
|
572
|
-
function getPath(o, path) {
|
|
573
|
-
let v = o;
|
|
574
|
-
for (const k of path.split(".")) {
|
|
575
|
-
if (v === null || typeof v !== "object") return void 0;
|
|
576
|
-
v = v[k];
|
|
577
|
-
}
|
|
578
|
-
return v;
|
|
579
|
-
}
|
|
580
|
-
function setPath(o, path, value) {
|
|
581
|
-
const keys = path.split(".");
|
|
582
|
-
let node = o;
|
|
583
|
-
for (const k of keys.slice(0, -1)) {
|
|
584
|
-
if (node[k] === null || typeof node[k] !== "object") node[k] = {};
|
|
585
|
-
node = node[k];
|
|
586
|
-
}
|
|
587
|
-
node[keys[keys.length - 1]] = value;
|
|
588
|
-
}
|
|
589
|
-
var copy = (v) => v !== null && typeof v === "object" ? JSON.parse(JSON.stringify(v)) : v;
|
|
590
|
-
function resolveEngine(brush) {
|
|
591
|
-
if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet";
|
|
592
|
-
if (_optionalChain([brush, 'access', _11 => _11.marks, 'optionalAccess', _12 => _12.kind]) === "particles") return "particle";
|
|
593
|
-
if (_optionalChain([brush, 'access', _13 => _13.marks, 'optionalAccess', _14 => _14.kind]) === "objects") return "sticker";
|
|
594
|
-
if (brush.tip.shape === "bristle") return "bristle";
|
|
595
|
-
const surface = _optionalChain([brush, 'access', _15 => _15.behaviour, 'optionalAccess', _16 => _16.surface]);
|
|
596
|
-
if (surface === "thick") return "impasto";
|
|
597
|
-
if (surface === "wet") return "wet";
|
|
598
|
-
if (_optionalChain([brush, 'access', _17 => _17.behaviour, 'optionalAccess', _18 => _18.exchange, 'optionalAccess', _19 => _19.reservoir])) return "mixer";
|
|
599
|
-
return "dab";
|
|
600
|
-
}
|
|
601
|
-
var VARIETY_CATEGORY = {
|
|
602
|
-
pencil: "pencil",
|
|
603
|
-
pastel: "pastel",
|
|
604
|
-
"soft-pastel": "pastel",
|
|
605
|
-
"oil-pastel": "pastel",
|
|
606
|
-
charcoal: "charcoal",
|
|
607
|
-
airbrush: "airbrush",
|
|
608
|
-
marker: "marker"
|
|
609
|
-
};
|
|
610
|
-
var MEDIUM_CATEGORY = { paint: "paint", ink: "ink", dry: "pencil", spray: "airbrush" };
|
|
611
|
-
function resolveWetMedium(brush) {
|
|
612
|
-
return _nullishCoalesce(_optionalChain([brush, 'access', _20 => _20.behaviour, 'optionalAccess', _21 => _21.wet, 'optionalAccess', _22 => _22.medium]), () => ( (_chunkHS6QDWDFcjs.WET_MEDIA.includes(brush.variety) ? brush.variety : void 0)));
|
|
613
|
-
}
|
|
614
|
-
function resolveCategory(brush, engine = resolveEngine(brush)) {
|
|
615
|
-
if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet-tool";
|
|
616
|
-
if ((_nullishCoalesce(_optionalChain([brush, 'access', _23 => _23.light, 'optionalAccess', _24 => _24.amount]), () => ( 0))) > 0) return "light";
|
|
617
|
-
switch (engine) {
|
|
618
|
-
case "particle":
|
|
619
|
-
return "procedural";
|
|
620
|
-
case "sticker":
|
|
621
|
-
return "sticker";
|
|
622
|
-
case "bristle":
|
|
623
|
-
return "bristle";
|
|
624
|
-
case "impasto":
|
|
625
|
-
return "impasto";
|
|
626
|
-
case "wet":
|
|
627
|
-
return resolveWetMedium(brush) === "oil" ? "oil" : "watercolor";
|
|
628
|
-
case "mixer":
|
|
629
|
-
return "mixer";
|
|
630
|
-
default:
|
|
631
|
-
return brush.variety && VARIETY_CATEGORY[brush.variety] || brush.medium && MEDIUM_CATEGORY[brush.medium] || "custom";
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
function resolveBrush(brush, options = {}) {
|
|
635
|
-
const engine = resolveEngine(brush);
|
|
636
|
-
const input = { id: brush.id, name: brush.name, category: resolveCategory(brush, engine), engine };
|
|
637
|
-
for (const field of BRUSH_FIELDS) {
|
|
638
|
-
if (!field.engines.includes(engine) || field.shapes && !field.shapes.includes(brush.tip.shape)) continue;
|
|
639
|
-
const v = getPath(brush, field.facet);
|
|
640
|
-
if (v !== void 0) setPath(input, field.engine, field.map ? field.map.toEngine(v) : copy(v));
|
|
641
|
-
}
|
|
642
|
-
if (engine === "wet") {
|
|
643
|
-
setPath(input, "wet.tool", brush.kind === "tool" ? WET_TOOL_OF[brush.tool] : "paint");
|
|
644
|
-
const medium = resolveWetMedium(brush);
|
|
645
|
-
if (medium) setPath(input, "wet.medium", medium);
|
|
646
|
-
}
|
|
647
|
-
if (engine === "blender" || engine === "smudge") input.loadsColor = false;
|
|
648
|
-
const paint = _optionalChain([brush, 'access', _25 => _25.colour, 'optionalAccess', _26 => _26.default]);
|
|
649
|
-
if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") input.paint = copy(paint);
|
|
650
|
-
return _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, { ...input, ...options.builtin ? { builtin: true } : {} });
|
|
651
|
-
}
|
|
652
262
|
|
|
653
|
-
// src/brushes/migrate.ts
|
|
654
|
-
var equal = (a, b) => a === b || JSON.stringify(a) === JSON.stringify(b);
|
|
655
|
-
var copy2 = (v) => v !== null && typeof v === "object" ? JSON.parse(JSON.stringify(v)) : v;
|
|
656
|
-
var CATEGORY_MEDIUM = {
|
|
657
|
-
pencil: ["dry", "pencil"],
|
|
658
|
-
pastel: ["dry", "pastel"],
|
|
659
|
-
charcoal: ["dry", "charcoal"],
|
|
660
|
-
airbrush: ["spray", "airbrush"],
|
|
661
|
-
marker: ["ink", "marker"],
|
|
662
|
-
ink: ["ink"],
|
|
663
|
-
paint: ["paint"]
|
|
664
|
-
};
|
|
665
|
-
function tipShape(b) {
|
|
666
|
-
if (b.engine === "bristle") return "bristle";
|
|
667
|
-
if (b.engine === "sticker" || b.engine === "particle" && b.particle.dotTextures.length > 0) return "stamp";
|
|
668
|
-
if (b.tip.roundness >= 1) return "round";
|
|
669
|
-
return Math.abs(Math.abs(b.tip.angle % 180) - 45) < 1e-9 || Math.abs(Math.abs(b.tip.angle % 180) - 135) < 1e-9 ? "chisel" : "flat";
|
|
670
|
-
}
|
|
671
|
-
function skeleton(b) {
|
|
672
|
-
const brush = { id: b.id, name: b.name, kind: "mark", tip: { shape: tipShape(b) } };
|
|
673
|
-
if (b.engine === "eraser" || b.engine === "blender" || b.engine === "smudge") return { ...brush, kind: "tool", tool: b.engine };
|
|
674
|
-
if (b.engine === "wet" && b.wet.tool !== "paint") {
|
|
675
|
-
const tool = Object.keys(WET_TOOL_OF).find((t) => WET_TOOL_OF[t] === b.wet.tool);
|
|
676
|
-
return { ...brush, kind: "tool", tool };
|
|
677
|
-
}
|
|
678
|
-
switch (b.engine) {
|
|
679
|
-
case "wet":
|
|
680
|
-
return { ...brush, medium: "paint", variety: b.wet.medium, behaviour: { surface: "wet" } };
|
|
681
|
-
case "impasto":
|
|
682
|
-
return { ...brush, medium: "paint", behaviour: { surface: "thick" } };
|
|
683
|
-
case "mixer":
|
|
684
|
-
return { ...brush, medium: "paint", variety: "mixer", behaviour: { exchange: { reservoir: {} } } };
|
|
685
|
-
case "bristle":
|
|
686
|
-
return { ...brush, medium: "paint" };
|
|
687
|
-
case "particle":
|
|
688
|
-
return { ...brush, marks: { kind: "particles" } };
|
|
689
|
-
case "sticker":
|
|
690
|
-
return { ...brush, marks: { kind: "objects" } };
|
|
691
|
-
default: {
|
|
692
|
-
const [medium, variety] = _nullishCoalesce(CATEGORY_MEDIUM[b.category], () => ( []));
|
|
693
|
-
return { ...brush, ...medium ? { medium } : {}, ...variety ? { variety } : {} };
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
var ORDER = ["id", "name", "description", "tags", "kind", "medium", "variety", "tool", "tip", "marks", "dynamics", "behaviour", "light", "motion", "colour"];
|
|
698
|
-
function migrateBrushV1(raw) {
|
|
699
|
-
const b = _chunkHS6QDWDFcjs.normalizePaintBrush.call(void 0, raw);
|
|
700
|
-
const brush = skeleton(b);
|
|
701
|
-
const defaults = resolveBrush(brush);
|
|
702
|
-
for (const field of BRUSH_FIELDS) {
|
|
703
|
-
if (!field.engines.includes(b.engine) || field.shapes && !field.shapes.includes(brush.tip.shape)) continue;
|
|
704
|
-
const v = getPath(b, field.engine);
|
|
705
|
-
if (!equal(v, getPath(defaults, field.engine))) setPath(brush, field.facet, field.map ? field.map.toFacet(v) : copy2(v));
|
|
706
|
-
}
|
|
707
|
-
if (b.paint) setPath(brush, "colour.default", copy2(b.paint));
|
|
708
|
-
return Object.fromEntries(ORDER.filter((k) => brush[k] !== void 0).map((k) => [k, brush[k]]));
|
|
709
|
-
}
|
|
710
263
|
|
|
711
|
-
// src/brushes/presets.ts
|
|
712
|
-
var BRUSH_PRESETS = [
|
|
713
|
-
{
|
|
714
|
-
id: "pencil-hb",
|
|
715
|
-
name: "HB pencil",
|
|
716
|
-
kind: "mark",
|
|
717
|
-
medium: "dry",
|
|
718
|
-
variety: "pencil",
|
|
719
|
-
tip: { shape: "round", size: 4, hardness: 0.7, spacing: 0.08, opacity: 0.85, flow: 0.55 },
|
|
720
|
-
dynamics: { smoothing: 0.25, pressureOpacity: true, pressureSmoothing: 0.3, minSize: 0.55, tiltSize: 0.9, tiltRoundness: 0.7, tiltOpacity: 0.5 },
|
|
721
|
-
behaviour: { grain: 0.85 }
|
|
722
|
-
},
|
|
723
|
-
{
|
|
724
|
-
id: "pencil-6b",
|
|
725
|
-
name: "6B pencil",
|
|
726
|
-
kind: "mark",
|
|
727
|
-
medium: "dry",
|
|
728
|
-
variety: "pencil",
|
|
729
|
-
tip: { shape: "round", size: 7, hardness: 0.55, spacing: 0.07, flow: 0.75 },
|
|
730
|
-
dynamics: { smoothing: 0.2, pressureOpacity: true, pressureSmoothing: 0.3, minSize: 0.5, tiltSize: 1, tiltRoundness: 0.75, tiltOpacity: 0.35 },
|
|
731
|
-
behaviour: { grain: 0.7 }
|
|
732
|
-
},
|
|
733
|
-
{
|
|
734
|
-
id: "soft-pastel",
|
|
735
|
-
name: "Soft pastel",
|
|
736
|
-
kind: "mark",
|
|
737
|
-
medium: "dry",
|
|
738
|
-
variety: "soft-pastel",
|
|
739
|
-
tip: { shape: "flat", size: 32, hardness: 0.55, spacing: 0.05, angle: 90, roundness: 0.55, flow: 0.7 },
|
|
740
|
-
dynamics: { smoothing: 0.15, pressureSize: false, pressureOpacity: true, pressureSmoothing: 0.25, rotation: "stroke", sizeJitter: 0.06, angleJitter: 0.02 },
|
|
741
|
-
behaviour: { grain: 1 }
|
|
742
|
-
},
|
|
743
|
-
{
|
|
744
|
-
id: "oil-pastel",
|
|
745
|
-
name: "Oil pastel",
|
|
746
|
-
kind: "mark",
|
|
747
|
-
medium: "dry",
|
|
748
|
-
variety: "oil-pastel",
|
|
749
|
-
tip: { shape: "flat", size: 26, hardness: 0.8, spacing: 0.05, angle: 90, roundness: 0.7, flow: 0.9, blend: "pigment" },
|
|
750
|
-
dynamics: { smoothing: 0.15, pressureSmoothing: 0.25, rotation: "stroke", minSize: 0.6 },
|
|
751
|
-
behaviour: { grain: 0.5 }
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
id: "charcoal-stick",
|
|
755
|
-
name: "Charcoal stick",
|
|
756
|
-
kind: "mark",
|
|
757
|
-
medium: "dry",
|
|
758
|
-
variety: "charcoal",
|
|
759
|
-
tip: { shape: "flat", size: 26, hardness: 0.4, spacing: 0.05, angle: 90, roundness: 0.35, opacity: 0.95, flow: 0.5 },
|
|
760
|
-
dynamics: { smoothing: 0.15, pressureSize: false, pressureOpacity: true, pressureSmoothing: 0.2, rotation: "stroke", tiltSize: 0.6, sizeJitter: 0.1, angleJitter: 0.03 },
|
|
761
|
-
behaviour: { grain: 0.95 }
|
|
762
|
-
},
|
|
763
|
-
{
|
|
764
|
-
id: "vine-charcoal",
|
|
765
|
-
name: "Vine charcoal",
|
|
766
|
-
kind: "mark",
|
|
767
|
-
medium: "dry",
|
|
768
|
-
variety: "charcoal",
|
|
769
|
-
tip: { shape: "round", size: 10, hardness: 0.3, spacing: 0.06, opacity: 0.75, flow: 0.45 },
|
|
770
|
-
dynamics: { smoothing: 0.2, pressureOpacity: true, pressureSmoothing: 0.2, minSize: 0.4, tiltSize: 0.8, tiltRoundness: 0.5, tiltOpacity: 0.3, sizeJitter: 0.08 },
|
|
771
|
-
behaviour: { grain: 0.9 }
|
|
772
|
-
},
|
|
773
|
-
{
|
|
774
|
-
id: "airbrush",
|
|
775
|
-
name: "Airbrush",
|
|
776
|
-
kind: "mark",
|
|
777
|
-
medium: "spray",
|
|
778
|
-
variety: "airbrush",
|
|
779
|
-
tip: { shape: "round", size: 90, hardness: 0, spacing: 0.04, flow: 0.06 },
|
|
780
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureSmoothing: 0.3, pressureFlow: 1, tiltSize: 0.5, tiltRoundness: 0.6 }
|
|
781
|
-
},
|
|
782
|
-
{
|
|
783
|
-
id: "marker",
|
|
784
|
-
name: "Chisel marker",
|
|
785
|
-
kind: "mark",
|
|
786
|
-
medium: "ink",
|
|
787
|
-
variety: "marker",
|
|
788
|
-
tip: { shape: "chisel", size: 24, hardness: 0.85, spacing: 0.04, angle: 45, roundness: 0.35, opacity: 0.6, blend: "multiply" },
|
|
789
|
-
dynamics: { smoothing: 0.3, pressureSize: false },
|
|
790
|
-
behaviour: { grain: 0.1 }
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
id: "ink-pen",
|
|
794
|
-
name: "Ink pen",
|
|
795
|
-
kind: "mark",
|
|
796
|
-
medium: "ink",
|
|
797
|
-
variety: "pen",
|
|
798
|
-
tip: { shape: "round", size: 4, spacing: 0.05 },
|
|
799
|
-
dynamics: { smoothing: 0.5, pressureSmoothing: 0.4, minSize: 0.25, velocitySize: -0.45 }
|
|
800
|
-
},
|
|
801
|
-
{
|
|
802
|
-
id: "brush-pen",
|
|
803
|
-
name: "Brush pen",
|
|
804
|
-
kind: "mark",
|
|
805
|
-
medium: "ink",
|
|
806
|
-
variety: "brush-pen",
|
|
807
|
-
tip: { shape: "flat", size: 14, hardness: 0.9, spacing: 0.04, roundness: 0.8 },
|
|
808
|
-
dynamics: { smoothing: 0.5, pressureSmoothing: 0.45, rotation: "stroke", minSize: 0.05, velocitySize: -0.3 }
|
|
809
|
-
},
|
|
810
|
-
{
|
|
811
|
-
id: "eraser-soft",
|
|
812
|
-
name: "Soft eraser",
|
|
813
|
-
kind: "tool",
|
|
814
|
-
tool: "eraser",
|
|
815
|
-
tip: { shape: "round", size: 40, hardness: 0.2, spacing: 0.08, flow: 0.6 },
|
|
816
|
-
dynamics: { pressureSize: false, pressureOpacity: true }
|
|
817
|
-
},
|
|
818
|
-
{
|
|
819
|
-
id: "eraser-hard",
|
|
820
|
-
name: "Hard eraser",
|
|
821
|
-
kind: "tool",
|
|
822
|
-
tool: "eraser",
|
|
823
|
-
tip: { shape: "round", size: 16, hardness: 0.9, spacing: 0.06 },
|
|
824
|
-
dynamics: { minSize: 0.5 },
|
|
825
|
-
behaviour: { grain: 0.3 }
|
|
826
|
-
},
|
|
827
|
-
{
|
|
828
|
-
id: "blender",
|
|
829
|
-
name: "Blender",
|
|
830
|
-
kind: "tool",
|
|
831
|
-
tool: "blender",
|
|
832
|
-
tip: { shape: "round", size: 34, hardness: 0.4 },
|
|
833
|
-
dynamics: { smoothing: 0.2, pressureSize: false, pressureOpacity: true }
|
|
834
|
-
},
|
|
835
|
-
{
|
|
836
|
-
id: "smudge",
|
|
837
|
-
name: "Smudge",
|
|
838
|
-
kind: "tool",
|
|
839
|
-
tool: "smudge",
|
|
840
|
-
tip: { shape: "round", size: 26, hardness: 0.6, spacing: 0.06 },
|
|
841
|
-
dynamics: { smoothing: 0.2, pressureSize: false, pressureOpacity: true },
|
|
842
|
-
behaviour: { strength: 0.75 }
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
id: "wet-smudge",
|
|
846
|
-
name: "Pigment smudge",
|
|
847
|
-
kind: "tool",
|
|
848
|
-
tool: "smudge",
|
|
849
|
-
tip: { shape: "round", size: 30, hardness: 0.5, spacing: 0.06 },
|
|
850
|
-
dynamics: { smoothing: 0.2, pressureOpacity: true, minSize: 0.6 },
|
|
851
|
-
behaviour: { length: 0.9, mixing: "pigment" }
|
|
852
|
-
},
|
|
853
|
-
{
|
|
854
|
-
id: "dirty-round",
|
|
855
|
-
name: "Dirty round",
|
|
856
|
-
kind: "mark",
|
|
857
|
-
medium: "paint",
|
|
858
|
-
variety: "acrylic",
|
|
859
|
-
tip: { shape: "round", size: 22, hardness: 0.65, spacing: 0.06, flow: 0.7 },
|
|
860
|
-
dynamics: { smoothing: 0.2, minSize: 0.5 },
|
|
861
|
-
behaviour: { exchange: { pickup: 0.55, mix: 0.6, dirty: true } }
|
|
862
|
-
},
|
|
863
|
-
// The paint and second colours side by side across the tip.
|
|
864
|
-
{
|
|
865
|
-
id: "multicolor-flat",
|
|
866
|
-
name: "Multi-colour flat",
|
|
867
|
-
kind: "mark",
|
|
868
|
-
medium: "paint",
|
|
869
|
-
variety: "acrylic",
|
|
870
|
-
tip: { shape: "flat", size: 30, hardness: 0.75, spacing: 0.05, angle: 90, roundness: 0.3, flow: 0.85 },
|
|
871
|
-
dynamics: { smoothing: 0.2, rotation: "stroke", minSize: 0.6 },
|
|
872
|
-
behaviour: { exchange: { pickup: 0.15, mix: 0.4 } },
|
|
873
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "paint" }, { offset: 1, color: "secondary" }], space: "pigment", map: { by: "across-tip" }, softness: 0.7 } }
|
|
874
|
-
},
|
|
875
|
-
// From the paint colour to the second colour and back, every 6 dabs.
|
|
876
|
-
{
|
|
877
|
-
id: "palette-dabber",
|
|
878
|
-
name: "Palette dabber",
|
|
879
|
-
kind: "mark",
|
|
880
|
-
medium: "paint",
|
|
881
|
-
variety: "acrylic",
|
|
882
|
-
tip: { shape: "round", size: 18, hardness: 0.7, spacing: 0.35, flow: 0.9 },
|
|
883
|
-
dynamics: { smoothing: 0.1, minSize: 0.5, sizeJitter: 0.15, scatter: 0.3 },
|
|
884
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "paint" }, { offset: 0.5, color: "secondary" }, { offset: 1, color: "paint" }], space: "pigment", map: { by: "distance", length: 12, repeat: "repeat", unit: "dabs" }, softness: 0.4 } }
|
|
885
|
-
},
|
|
886
|
-
// Changes colour as it is dragged out: paint → second colour over 300 px, and back.
|
|
887
|
-
{
|
|
888
|
-
id: "gradient-round",
|
|
889
|
-
name: "Gradient round",
|
|
890
|
-
kind: "mark",
|
|
891
|
-
medium: "paint",
|
|
892
|
-
variety: "gradient",
|
|
893
|
-
tip: { shape: "round", size: 24, hardness: 0.8, spacing: 0.05, flow: 0.9 },
|
|
894
|
-
dynamics: { smoothing: 0.2, minSize: 0.5 },
|
|
895
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "paint" }, { offset: 1, color: "secondary" }], space: "pigment", map: { by: "distance", length: 300, repeat: "mirror", unit: "px" } } }
|
|
896
|
-
},
|
|
897
|
-
// Light pressure lays the second colour, full pressure the paint colour.
|
|
898
|
-
{
|
|
899
|
-
id: "pressure-ombre",
|
|
900
|
-
name: "Pressure ombr\xE9",
|
|
901
|
-
kind: "mark",
|
|
902
|
-
medium: "paint",
|
|
903
|
-
variety: "gradient",
|
|
904
|
-
tip: { shape: "round", size: 26, hardness: 0.6, spacing: 0.05, flow: 0.8 },
|
|
905
|
-
dynamics: { smoothing: 0.2, pressureSize: false },
|
|
906
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "secondary" }, { offset: 1, color: "paint" }], space: "pigment", map: { by: "pressure" } } }
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
id: "rainbow-marker",
|
|
910
|
-
name: "Rainbow marker",
|
|
911
|
-
kind: "mark",
|
|
912
|
-
medium: "ink",
|
|
913
|
-
variety: "marker",
|
|
914
|
-
tip: { shape: "flat", size: 18, hardness: 0.9, spacing: 0.04, angle: 90, roundness: 0.4 },
|
|
915
|
-
dynamics: { smoothing: 0.25, pressureSize: false, rotation: "stroke" },
|
|
916
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "#e11d48" }, { offset: 0.2, color: "#f59e0b" }, { offset: 0.4, color: "#facc15" }, { offset: 0.6, color: "#22c55e" }, { offset: 0.8, color: "#3b82f6" }, { offset: 1, color: "#8b5cf6" }], space: "oklab", map: { by: "distance", length: 600, repeat: "repeat", unit: "px" } }, own: true }
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
id: "mixer-brush",
|
|
920
|
-
name: "Mixer Brush",
|
|
921
|
-
kind: "mark",
|
|
922
|
-
medium: "paint",
|
|
923
|
-
variety: "mixer",
|
|
924
|
-
tip: { shape: "round", size: 30, hardness: 0.7, flow: 0.5 },
|
|
925
|
-
dynamics: { smoothing: 0.2, minSize: 0.5 },
|
|
926
|
-
behaviour: { exchange: { reservoir: { load: 0.95 } }, mixing: "pigment" }
|
|
927
|
-
},
|
|
928
|
-
{
|
|
929
|
-
id: "watercolor-round",
|
|
930
|
-
name: "Watercolour round",
|
|
931
|
-
kind: "mark",
|
|
932
|
-
medium: "paint",
|
|
933
|
-
variety: "watercolor",
|
|
934
|
-
tip: { shape: "round", size: 28, hardness: 0.6, spacing: 0.12 },
|
|
935
|
-
dynamics: { smoothing: 0.25, pressureOpacity: true, minSize: 0.35 },
|
|
936
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.55 }, wet: { water: 0.55, rewet: 0.2 } }
|
|
937
|
-
},
|
|
938
|
-
{
|
|
939
|
-
id: "watercolor-wash",
|
|
940
|
-
name: "Wash brush",
|
|
941
|
-
kind: "mark",
|
|
942
|
-
medium: "paint",
|
|
943
|
-
variety: "watercolor",
|
|
944
|
-
tip: { shape: "flat", size: 90, hardness: 0.35, angle: 90, roundness: 0.45 },
|
|
945
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureOpacity: true, rotation: "stroke" },
|
|
946
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.45, mix: 0.45 }, wet: { water: 0.8, pigment: 0.45, rewet: 0.2 } }
|
|
947
|
-
},
|
|
948
|
-
// A graded wash: the paint colour runs into the second colour as the brush travels.
|
|
949
|
-
{
|
|
950
|
-
id: "gradient-wash",
|
|
951
|
-
name: "Gradient wash",
|
|
952
|
-
kind: "mark",
|
|
953
|
-
medium: "paint",
|
|
954
|
-
variety: "watercolor",
|
|
955
|
-
tip: { shape: "flat", size: 80, hardness: 0.35, angle: 90, roundness: 0.5 },
|
|
956
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureOpacity: true, rotation: "stroke" },
|
|
957
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.4, mix: 0.4 }, wet: { water: 0.8, pigment: 0.45, rewet: 0.2 } },
|
|
958
|
-
colour: { default: { type: "gradient", stops: [{ offset: 0, color: "paint" }, { offset: 1, color: "secondary" }], space: "pigment", map: { by: "distance", length: 500, repeat: "mirror", unit: "px" } } }
|
|
959
|
-
},
|
|
960
|
-
{
|
|
961
|
-
id: "watercolor-detail",
|
|
962
|
-
name: "Watercolour rigger",
|
|
963
|
-
kind: "mark",
|
|
964
|
-
medium: "paint",
|
|
965
|
-
variety: "watercolor",
|
|
966
|
-
tip: { shape: "round", size: 7, hardness: 0.75 },
|
|
967
|
-
dynamics: { smoothing: 0.4, minSize: 0.2 },
|
|
968
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.4, mix: 0.45 }, wet: { water: 0.4, pigment: 0.7, rewet: 0.2 } }
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
id: "gouache",
|
|
972
|
-
name: "Gouache",
|
|
973
|
-
kind: "mark",
|
|
974
|
-
medium: "paint",
|
|
975
|
-
variety: "gouache",
|
|
976
|
-
tip: { shape: "round", size: 26, hardness: 0.7 },
|
|
977
|
-
dynamics: { smoothing: 0.25, minSize: 0.5 },
|
|
978
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.65, mix: 0.6 }, wet: { water: 0.35, pigment: 0.8, body: 1, rewet: 0.3 } }
|
|
979
|
-
},
|
|
980
|
-
{
|
|
981
|
-
id: "oil-round",
|
|
982
|
-
name: "Wet oil round",
|
|
983
|
-
kind: "mark",
|
|
984
|
-
medium: "paint",
|
|
985
|
-
variety: "oil",
|
|
986
|
-
tip: { shape: "round", size: 24, hardness: 0.75, spacing: 0.08 },
|
|
987
|
-
dynamics: { smoothing: 0.25, minSize: 0.5 },
|
|
988
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.6, mix: 0.55 }, wet: { water: 0.4, pigment: 0.9, body: 1, load: 0.97 } }
|
|
989
|
-
},
|
|
990
|
-
{
|
|
991
|
-
id: "oil-flat",
|
|
992
|
-
name: "Wet oil flat",
|
|
993
|
-
kind: "mark",
|
|
994
|
-
medium: "paint",
|
|
995
|
-
variety: "oil",
|
|
996
|
-
tip: { shape: "flat", size: 40, hardness: 0.85, spacing: 0.06, angle: 90, roundness: 0.35 },
|
|
997
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.6 },
|
|
998
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.65, mix: 0.6 }, wet: { water: 0.45, pigment: 0.9, body: 1, load: 0.95 } }
|
|
999
|
-
},
|
|
1000
|
-
{
|
|
1001
|
-
id: "impasto-brush",
|
|
1002
|
-
name: "Impasto brush",
|
|
1003
|
-
kind: "mark",
|
|
1004
|
-
medium: "paint",
|
|
1005
|
-
variety: "oil",
|
|
1006
|
-
tip: { shape: "flat", size: 36, hardness: 0.8, spacing: 0.06, angle: 90, roundness: 0.55 },
|
|
1007
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.55 },
|
|
1008
|
-
behaviour: { surface: "thick", exchange: { pickup: 0.4 }, thick: { gloss: 0.45, load: 0.92 } }
|
|
1009
|
-
},
|
|
1010
|
-
{
|
|
1011
|
-
id: "paint-tube",
|
|
1012
|
-
name: "Paint tube",
|
|
1013
|
-
kind: "mark",
|
|
1014
|
-
medium: "paint",
|
|
1015
|
-
variety: "oil",
|
|
1016
|
-
tip: { shape: "round", size: 22, hardness: 0.9, spacing: 0.05 },
|
|
1017
|
-
dynamics: { smoothing: 0.35, minSize: 0.4 },
|
|
1018
|
-
behaviour: { surface: "thick", thick: { applicator: "tube", thickness: 0.9, gloss: 0.5, load: 1, drag: 0.1 } }
|
|
1019
|
-
},
|
|
1020
|
-
{
|
|
1021
|
-
id: "palette-knife",
|
|
1022
|
-
name: "Palette knife",
|
|
1023
|
-
kind: "mark",
|
|
1024
|
-
medium: "paint",
|
|
1025
|
-
variety: "oil",
|
|
1026
|
-
tip: { shape: "flat", size: 48, spacing: 0.05, angle: 90, roundness: 0.18 },
|
|
1027
|
-
dynamics: { smoothing: 0.3, pressureSize: false, rotation: "stroke" },
|
|
1028
|
-
behaviour: { surface: "thick", thick: { applicator: "knife", thickness: 0.3, gloss: 0.55, load: 1, drag: 0.85 } }
|
|
1029
|
-
},
|
|
1030
|
-
{
|
|
1031
|
-
id: "paint-roller",
|
|
1032
|
-
name: "Roller",
|
|
1033
|
-
kind: "mark",
|
|
1034
|
-
medium: "paint",
|
|
1035
|
-
variety: "acrylic",
|
|
1036
|
-
tip: { shape: "flat", size: 70, hardness: 0.95, spacing: 0.04, angle: 90, roundness: 0.12 },
|
|
1037
|
-
dynamics: { smoothing: 0.4, pressureSize: false, rotation: "stroke" },
|
|
1038
|
-
behaviour: { surface: "thick", thick: { applicator: "roller", thickness: 0.25, gloss: 0.3, drag: 0.15 } }
|
|
1039
|
-
},
|
|
1040
|
-
{
|
|
1041
|
-
id: "gloop-pen",
|
|
1042
|
-
name: "Gloop pen",
|
|
1043
|
-
kind: "mark",
|
|
1044
|
-
medium: "paint",
|
|
1045
|
-
variety: "gloop",
|
|
1046
|
-
tip: { shape: "round", size: 14, hardness: 0.9, spacing: 0.05 },
|
|
1047
|
-
dynamics: { smoothing: 0.5, minSize: 0.5 },
|
|
1048
|
-
behaviour: { surface: "thick", thick: { applicator: "gloop", thickness: 1, gloss: 0.9, load: 1, drag: 0 } }
|
|
1049
|
-
},
|
|
1050
|
-
{
|
|
1051
|
-
id: "metallic-paint",
|
|
1052
|
-
name: "Metallic paint",
|
|
1053
|
-
kind: "mark",
|
|
1054
|
-
medium: "paint",
|
|
1055
|
-
variety: "metallic",
|
|
1056
|
-
tip: { shape: "flat", size: 30, hardness: 0.8, spacing: 0.06, angle: 90, roundness: 0.6 },
|
|
1057
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.5 },
|
|
1058
|
-
behaviour: { surface: "thick", exchange: { pickup: 0.2, mix: 0.4 }, thick: { thickness: 0.45, gloss: 0.8, metallic: 1, load: 0.95, drag: 0.3 } }
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
id: "hair-strands",
|
|
1062
|
-
name: "Hair strands",
|
|
1063
|
-
kind: "mark",
|
|
1064
|
-
medium: "ink",
|
|
1065
|
-
variety: "hair",
|
|
1066
|
-
tip: { shape: "round", size: 40, hardness: 0.8, opacity: 0.9, flow: 0.6 },
|
|
1067
|
-
marks: { kind: "particles", physics: "string", count: 22, size: 0.025, spread: 1, stiffness: 0.08, damping: 0.3 },
|
|
1068
|
-
dynamics: { smoothing: 0.2, pressureOpacity: true }
|
|
1069
|
-
},
|
|
1070
|
-
{
|
|
1071
|
-
id: "spring-ink",
|
|
1072
|
-
name: "Spring ink",
|
|
1073
|
-
kind: "mark",
|
|
1074
|
-
medium: "ink",
|
|
1075
|
-
variety: "spring",
|
|
1076
|
-
tip: { shape: "round", size: 30, hardness: 0.9, flow: 0.8 },
|
|
1077
|
-
marks: { kind: "particles", count: 5, spread: 0.6, stiffness: 0.2, damping: 0.1 },
|
|
1078
|
-
dynamics: { smoothing: 0.1 }
|
|
1079
|
-
},
|
|
1080
|
-
{
|
|
1081
|
-
id: "orbit-curls",
|
|
1082
|
-
name: "Orbit curls",
|
|
1083
|
-
kind: "mark",
|
|
1084
|
-
medium: "ink",
|
|
1085
|
-
variety: "curls",
|
|
1086
|
-
tip: { shape: "round", size: 36, hardness: 0.85, opacity: 0.9, flow: 0.7 },
|
|
1087
|
-
marks: { kind: "particles", physics: "orbit", count: 4, size: 0.05, spread: 0.6, speed: 0.45 },
|
|
1088
|
-
dynamics: { smoothing: 0.2 }
|
|
1089
|
-
},
|
|
1090
|
-
{
|
|
1091
|
-
id: "flow-fur",
|
|
1092
|
-
name: "Flow fur",
|
|
1093
|
-
kind: "mark",
|
|
1094
|
-
medium: "ink",
|
|
1095
|
-
variety: "fur",
|
|
1096
|
-
tip: { shape: "round", size: 50, hardness: 0.7, opacity: 0.8, flow: 0.5 },
|
|
1097
|
-
marks: { kind: "particles", physics: "flow", count: 10, size: 0.03, spread: 0.6, life: 0.25 },
|
|
1098
|
-
dynamics: { smoothing: 0.2, pressureOpacity: true }
|
|
1099
|
-
},
|
|
1100
|
-
{
|
|
1101
|
-
id: "bead-trail",
|
|
1102
|
-
name: "Bead trail",
|
|
1103
|
-
kind: "mark",
|
|
1104
|
-
medium: "paint",
|
|
1105
|
-
variety: "beads",
|
|
1106
|
-
tip: { shape: "round", size: 34, hardness: 0.9 },
|
|
1107
|
-
marks: { kind: "particles", render: "sequence", count: 3, size: 0.18, stiffness: 0.3, damping: 0.3, interval: 0.4 },
|
|
1108
|
-
dynamics: { smoothing: 0.25 }
|
|
1109
|
-
},
|
|
1110
|
-
{
|
|
1111
|
-
id: "sparkle-dust",
|
|
1112
|
-
name: "Sparkle dust",
|
|
1113
|
-
kind: "mark",
|
|
1114
|
-
medium: "paint",
|
|
1115
|
-
variety: "glitter",
|
|
1116
|
-
tip: { shape: "round", size: 60, hardness: 0.6, flow: 0.9 },
|
|
1117
|
-
marks: { kind: "particles", physics: "flow", render: "dot", count: 6, size: 0.05, spread: 0.9, speed: 0.7, life: 0.4 },
|
|
1118
|
-
dynamics: { smoothing: 0.1, pressureOpacity: true }
|
|
1119
|
-
},
|
|
1120
|
-
{
|
|
1121
|
-
id: "bristle-round",
|
|
1122
|
-
name: "Bristle round",
|
|
1123
|
-
kind: "mark",
|
|
1124
|
-
medium: "paint",
|
|
1125
|
-
variety: "oil",
|
|
1126
|
-
tip: { shape: "bristle", size: 30, hardness: 0.85, flow: 0.9, bristle: { count: 28, stiffness: 0.45, splay: 0.6, thickness: 0.035, load: 0.7, jitter: 0.5 } },
|
|
1127
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.4, tiltSize: 0.6, tiltRoundness: 0.6 }
|
|
1128
|
-
},
|
|
1129
|
-
{
|
|
1130
|
-
id: "bristle-flat",
|
|
1131
|
-
name: "Bristle flat",
|
|
1132
|
-
kind: "mark",
|
|
1133
|
-
medium: "paint",
|
|
1134
|
-
variety: "oil",
|
|
1135
|
-
tip: { shape: "bristle", size: 46, hardness: 0.85, angle: 90, roundness: 0.3, flow: 0.9, bristle: { count: 40, stiffness: 0.6, splay: 0.4, thickness: 0.025, load: 0.65, jitter: 0.45 } },
|
|
1136
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.5, tiltSize: 0.5 }
|
|
1137
|
-
},
|
|
1138
|
-
{
|
|
1139
|
-
id: "dry-brush",
|
|
1140
|
-
name: "Dry brush",
|
|
1141
|
-
kind: "mark",
|
|
1142
|
-
medium: "paint",
|
|
1143
|
-
variety: "dry-brush",
|
|
1144
|
-
tip: { shape: "bristle", size: 44, hardness: 0.9, angle: 90, roundness: 0.45, flow: 0.8, bristle: { count: 48, stiffness: 0.35, splay: 0.7, thickness: 0.05, load: 0.15, jitter: 0.8 } },
|
|
1145
|
-
dynamics: { smoothing: 0.2, rotation: "stroke" },
|
|
1146
|
-
behaviour: { grain: 0.6 }
|
|
1147
|
-
},
|
|
1148
|
-
// Light paint: brushes that lay light with their colour (glow and spill; see light.ts).
|
|
1149
|
-
{
|
|
1150
|
-
id: "glow-gel",
|
|
1151
|
-
name: "Glow gel",
|
|
1152
|
-
kind: "mark",
|
|
1153
|
-
medium: "paint",
|
|
1154
|
-
variety: "gel",
|
|
1155
|
-
tip: { shape: "round", size: 16, hardness: 0.9, spacing: 0.05 },
|
|
1156
|
-
dynamics: { smoothing: 0.5, minSize: 0.6 },
|
|
1157
|
-
behaviour: { surface: "thick", thick: { applicator: "gloop", thickness: 1, gloss: 0.95, load: 1, drag: 0, rim: 0.8, clarity: 0.5 } },
|
|
1158
|
-
light: { amount: 0.85 }
|
|
1159
|
-
},
|
|
1160
|
-
{
|
|
1161
|
-
id: "neon-marker",
|
|
1162
|
-
name: "Neon marker",
|
|
1163
|
-
kind: "mark",
|
|
1164
|
-
medium: "ink",
|
|
1165
|
-
variety: "neon",
|
|
1166
|
-
tip: { shape: "round", size: 10, hardness: 0.9, spacing: 0.04 },
|
|
1167
|
-
dynamics: { smoothing: 0.45, pressureSize: false },
|
|
1168
|
-
light: { amount: 1 }
|
|
1169
|
-
},
|
|
1170
|
-
{
|
|
1171
|
-
id: "light-airbrush",
|
|
1172
|
-
name: "Light airbrush",
|
|
1173
|
-
kind: "mark",
|
|
1174
|
-
medium: "spray",
|
|
1175
|
-
variety: "airbrush",
|
|
1176
|
-
tip: { shape: "round", size: 90, hardness: 0, spacing: 0.04, flow: 0.06 },
|
|
1177
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureSmoothing: 0.3, pressureFlow: 1 },
|
|
1178
|
-
light: { amount: 0.7, pressure: true }
|
|
1179
|
-
},
|
|
1180
|
-
{
|
|
1181
|
-
id: "spark-trail",
|
|
1182
|
-
name: "Spark trail",
|
|
1183
|
-
kind: "mark",
|
|
1184
|
-
medium: "paint",
|
|
1185
|
-
variety: "sparks",
|
|
1186
|
-
tip: { shape: "round", size: 50, hardness: 0.7 },
|
|
1187
|
-
marks: { kind: "particles", physics: "flow", render: "dot", count: 8, size: 0.06, spread: 0.7, speed: 0.9, life: 0.3 },
|
|
1188
|
-
dynamics: { smoothing: 0.1 },
|
|
1189
|
-
light: { amount: 1 }
|
|
1190
|
-
},
|
|
1191
|
-
// Silk of light: strands dragged behind the pen on slow waves, the bands between them filled.
|
|
1192
|
-
{
|
|
1193
|
-
id: "light-ribbon",
|
|
1194
|
-
name: "Light ribbon",
|
|
1195
|
-
kind: "mark",
|
|
1196
|
-
medium: "paint",
|
|
1197
|
-
variety: "ribbon",
|
|
1198
|
-
tip: { shape: "round", size: 80, hardness: 0.8, opacity: 0.9 },
|
|
1199
|
-
marks: { kind: "particles", physics: "string", render: "ribbon", count: 5, size: 0.015, spread: 1, stiffness: 0.05, damping: 0.3, ribbonFill: 0.45, waveAmplitude: 0.25, waveLength: 220, wavePhaseJitter: 0.25 },
|
|
1200
|
-
dynamics: { smoothing: 0.35, pressureSize: false },
|
|
1201
|
-
light: { amount: 0.8 }
|
|
1202
|
-
},
|
|
1203
|
-
// Flames: short-lived bands thrown off the pen, rising and curling in the flow.
|
|
1204
|
-
{
|
|
1205
|
-
id: "flame-ribbon",
|
|
1206
|
-
name: "Flame ribbon",
|
|
1207
|
-
kind: "mark",
|
|
1208
|
-
medium: "paint",
|
|
1209
|
-
variety: "flame",
|
|
1210
|
-
tip: { shape: "round", size: 50, hardness: 0.6, opacity: 0.85 },
|
|
1211
|
-
marks: { kind: "particles", physics: "flow", render: "ribbon", count: 4, size: 0.012, speed: 0.6, gravity: -0.6, life: 0.2 },
|
|
1212
|
-
dynamics: { smoothing: 0.25 },
|
|
1213
|
-
light: { amount: 1 }
|
|
1214
|
-
},
|
|
1215
|
-
// A neon tube that lags and snaps back, with a slow shimmer.
|
|
1216
|
-
{
|
|
1217
|
-
id: "neon-strand",
|
|
1218
|
-
name: "Neon strand",
|
|
1219
|
-
kind: "mark",
|
|
1220
|
-
medium: "ink",
|
|
1221
|
-
variety: "neon",
|
|
1222
|
-
tip: { shape: "round", size: 40, hardness: 0.9 },
|
|
1223
|
-
marks: { kind: "particles", physics: "elastic", count: 3, size: 0.05, spread: 0.25, stiffness: 0.6, damping: 0.3, waveAmplitude: 0.06, waveLength: 120 },
|
|
1224
|
-
dynamics: { smoothing: 0.4, pressureSize: false },
|
|
1225
|
-
light: { amount: 1 }
|
|
1226
|
-
},
|
|
1227
|
-
// Smoke lit from within: thin bands thrown into a slow, rising flow.
|
|
1228
|
-
{
|
|
1229
|
-
id: "smoke-ribbon",
|
|
1230
|
-
name: "Smoke ribbon",
|
|
1231
|
-
kind: "mark",
|
|
1232
|
-
medium: "paint",
|
|
1233
|
-
variety: "smoke",
|
|
1234
|
-
tip: { shape: "round", size: 70, hardness: 0.3, opacity: 0.45 },
|
|
1235
|
-
marks: { kind: "particles", physics: "flow", render: "ribbon", count: 3, size: 5e-3, speed: 0.15, gravity: -0.15, life: 0.35, ribbonFill: 0.25, waveAmplitude: 0.1, waveLength: 140, wavePhaseJitter: 1 },
|
|
1236
|
-
dynamics: { smoothing: 0.3 },
|
|
1237
|
-
light: { amount: 0.3 }
|
|
1238
|
-
},
|
|
1239
|
-
// Out-of-focus lights: soft discs and rings spaced along springy paths.
|
|
1240
|
-
{
|
|
1241
|
-
id: "bokeh-dots",
|
|
1242
|
-
name: "Bokeh dots",
|
|
1243
|
-
kind: "mark",
|
|
1244
|
-
medium: "paint",
|
|
1245
|
-
variety: "bokeh",
|
|
1246
|
-
tip: { shape: "stamp", size: 80, hardness: 0.7, opacity: 0.6, stamps: ["editor:dot", "editor:dot", "editor:ring"] },
|
|
1247
|
-
marks: { kind: "particles", render: "sequence", count: 3, size: 0.3, spread: 1, stiffness: 0.15, damping: 0.4, interval: 1, stampOrder: "random" },
|
|
1248
|
-
dynamics: { smoothing: 0.3 },
|
|
1249
|
-
light: { amount: 0.9 }
|
|
1250
|
-
},
|
|
1251
|
-
// Sparks: twinkles and stars thrown into the flow, spaced along it.
|
|
1252
|
-
{
|
|
1253
|
-
id: "twinkle-sparks",
|
|
1254
|
-
name: "Twinkle sparks",
|
|
1255
|
-
kind: "mark",
|
|
1256
|
-
medium: "paint",
|
|
1257
|
-
variety: "sparks",
|
|
1258
|
-
tip: { shape: "stamp", size: 50, hardness: 0.8, stamps: ["editor:sparkle", "editor:sparkle", "editor:star"] },
|
|
1259
|
-
marks: { kind: "particles", physics: "flow", render: "sequence", count: 3, size: 0.25, spread: 0.8, speed: 0.9, life: 0.35, interval: 0.6, stampOrder: "random" },
|
|
1260
|
-
dynamics: { smoothing: 0.1 },
|
|
1261
|
-
light: { amount: 1 }
|
|
1262
|
-
},
|
|
1263
|
-
{
|
|
1264
|
-
id: "glow-wash",
|
|
1265
|
-
name: "Glow wash",
|
|
1266
|
-
kind: "mark",
|
|
1267
|
-
medium: "paint",
|
|
1268
|
-
variety: "watercolor",
|
|
1269
|
-
tip: { shape: "round", size: 40, hardness: 0.55, spacing: 0.12 },
|
|
1270
|
-
dynamics: { smoothing: 0.25, pressureOpacity: true, minSize: 0.35 },
|
|
1271
|
-
behaviour: { surface: "wet", exchange: { pickup: 0.4 }, wet: { water: 0.65, pigment: 0.75, rewet: 0.1 } },
|
|
1272
|
-
light: { amount: 0.7 }
|
|
1273
|
-
},
|
|
1274
|
-
// Fluorescent ink: a transparent chisel marker that multiplies (text under it stays dark) and glows a little
|
|
1275
|
-
// brighter than the paper. Its light spills nowhere (a spill hint of 0), and it comes in highlighter colours.
|
|
1276
|
-
{
|
|
1277
|
-
id: "highlighter",
|
|
1278
|
-
name: "Highlighter",
|
|
1279
|
-
kind: "mark",
|
|
1280
|
-
medium: "ink",
|
|
1281
|
-
variety: "highlighter",
|
|
1282
|
-
tip: { shape: "chisel", size: 30, hardness: 0.85, spacing: 0.04, angle: 45, roundness: 0.35, opacity: 0.6, blend: "multiply" },
|
|
1283
|
-
dynamics: { smoothing: 0.3, pressureSize: false },
|
|
1284
|
-
behaviour: { grain: 0.05 },
|
|
1285
|
-
light: { amount: 0.5, spill: { radius: 0 } },
|
|
1286
|
-
colour: { default: "#fff200", palette: ["#fff200", "#ff6ec7", "#7cff4f", "#ffa630"] }
|
|
1287
|
-
},
|
|
1288
|
-
{
|
|
1289
|
-
id: "sticker-stars",
|
|
1290
|
-
name: "Star stickers",
|
|
1291
|
-
kind: "mark",
|
|
1292
|
-
variety: "stars",
|
|
1293
|
-
tip: { shape: "stamp", size: 36, stamps: ["editor:star", "editor:sparkle"] },
|
|
1294
|
-
marks: { kind: "objects", density: 0.35, sizeJitter: 0.5, scatter: 0.6, colourJitter: 0.3 },
|
|
1295
|
-
dynamics: { smoothing: 0.2, minSize: 0.5 }
|
|
1296
|
-
},
|
|
1297
|
-
{
|
|
1298
|
-
id: "sticker-leaves",
|
|
1299
|
-
name: "Leaf stickers",
|
|
1300
|
-
kind: "mark",
|
|
1301
|
-
variety: "leaves",
|
|
1302
|
-
tip: { shape: "stamp", size: 40, stamps: ["editor:leaf"] },
|
|
1303
|
-
marks: { kind: "objects", density: 0.5, rotationJitter: 0.35, scatter: 0.4, colourJitter: 0.35 },
|
|
1304
|
-
dynamics: { smoothing: 0.25, rotation: "stroke", minSize: 0.5 }
|
|
1305
|
-
},
|
|
1306
|
-
{
|
|
1307
|
-
id: "sticker-confetti",
|
|
1308
|
-
name: "Confetti",
|
|
1309
|
-
kind: "mark",
|
|
1310
|
-
variety: "confetti",
|
|
1311
|
-
tip: { shape: "stamp", size: 22, stamps: ["editor:confetti", "editor:dot", "editor:ring"] },
|
|
1312
|
-
marks: { kind: "objects", density: 0.7, sizeJitter: 0.5, scatter: 1.5, colourJitter: 1 },
|
|
1313
|
-
dynamics: { smoothing: 0.1, pressureSize: false }
|
|
1314
|
-
},
|
|
1315
|
-
{
|
|
1316
|
-
id: "sticker-flowers",
|
|
1317
|
-
name: "Flower stickers",
|
|
1318
|
-
kind: "mark",
|
|
1319
|
-
variety: "flowers",
|
|
1320
|
-
tip: { shape: "stamp", size: 44, stamps: ["editor:flower", "editor:heart"] },
|
|
1321
|
-
marks: { kind: "objects", density: 0.3, sizeJitter: 0.5, scatter: 0.7, colourJitter: 0.4 },
|
|
1322
|
-
dynamics: { smoothing: 0.2 }
|
|
1323
|
-
},
|
|
1324
|
-
{
|
|
1325
|
-
id: "sticker-splats",
|
|
1326
|
-
name: "Paint splats",
|
|
1327
|
-
kind: "mark",
|
|
1328
|
-
variety: "splats",
|
|
1329
|
-
tip: { shape: "stamp", size: 50, opacity: 0.95, stamps: ["editor:splat"] },
|
|
1330
|
-
marks: { kind: "objects", density: 0.25, sizeJitter: 0.6, scatter: 0.8, colourJitter: 0.15 },
|
|
1331
|
-
dynamics: { smoothing: 0.1 }
|
|
1332
|
-
},
|
|
1333
|
-
{
|
|
1334
|
-
id: "add-water",
|
|
1335
|
-
name: "Add water",
|
|
1336
|
-
kind: "tool",
|
|
1337
|
-
tool: "water",
|
|
1338
|
-
tip: { shape: "round", size: 40, hardness: 0.4, spacing: 0.12 },
|
|
1339
|
-
dynamics: { smoothing: 0.25, pressureOpacity: true, minSize: 0.5 },
|
|
1340
|
-
behaviour: { wet: { water: 0.6, pigment: 0, rewet: 0.3 } }
|
|
1341
|
-
},
|
|
1342
|
-
{
|
|
1343
|
-
id: "hair-dryer",
|
|
1344
|
-
name: "Dry",
|
|
1345
|
-
kind: "tool",
|
|
1346
|
-
tool: "dryer",
|
|
1347
|
-
tip: { shape: "round", size: 80, hardness: 0.1, spacing: 0.15 },
|
|
1348
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureOpacity: true }
|
|
1349
|
-
},
|
|
1350
|
-
{
|
|
1351
|
-
id: "blow",
|
|
1352
|
-
name: "Blow",
|
|
1353
|
-
kind: "tool",
|
|
1354
|
-
tool: "blow",
|
|
1355
|
-
tip: { shape: "round", size: 50, hardness: 0.2 },
|
|
1356
|
-
dynamics: { smoothing: 0.3, pressureSize: false, pressureOpacity: true },
|
|
1357
|
-
behaviour: { strength: 0.6 }
|
|
1358
|
-
},
|
|
1359
|
-
{
|
|
1360
|
-
id: "wet-blend",
|
|
1361
|
-
name: "Wet blend",
|
|
1362
|
-
kind: "tool",
|
|
1363
|
-
tool: "wet-blend",
|
|
1364
|
-
tip: { shape: "round", size: 36, hardness: 0.3 },
|
|
1365
|
-
dynamics: { smoothing: 0.25, pressureSize: false, pressureOpacity: true },
|
|
1366
|
-
behaviour: { strength: 0.4 }
|
|
1367
|
-
},
|
|
1368
|
-
{
|
|
1369
|
-
id: "wet-drag",
|
|
1370
|
-
name: "Wet smudge",
|
|
1371
|
-
kind: "tool",
|
|
1372
|
-
tool: "wet-drag",
|
|
1373
|
-
tip: { shape: "round", size: 30, hardness: 0.5, spacing: 0.08 },
|
|
1374
|
-
dynamics: { smoothing: 0.25, pressureSize: false, pressureOpacity: true },
|
|
1375
|
-
behaviour: { strength: 0.6 }
|
|
1376
|
-
},
|
|
1377
|
-
{
|
|
1378
|
-
id: "blot",
|
|
1379
|
-
name: "Blot (erase wet)",
|
|
1380
|
-
kind: "tool",
|
|
1381
|
-
tool: "blot",
|
|
1382
|
-
tip: { shape: "round", size: 40, hardness: 0.5, spacing: 0.12 },
|
|
1383
|
-
dynamics: { smoothing: 0.2, pressureSize: false, pressureOpacity: true },
|
|
1384
|
-
behaviour: { strength: 0.7 }
|
|
1385
|
-
}
|
|
1386
|
-
];
|
|
1387
264
|
|
|
1388
265
|
|
|
1389
266
|
|
|
@@ -1403,4 +280,23 @@ var BRUSH_PRESETS = [
|
|
|
1403
280
|
|
|
1404
281
|
|
|
1405
282
|
|
|
1406
|
-
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
exports.BRUSH_FACET_SCHEMAS = _chunk34KLWUH4cjs.BRUSH_FACET_SCHEMAS; exports.BRUSH_HOST_PROFILES = _chunk34KLWUH4cjs.BRUSH_HOST_PROFILES; exports.BRUSH_JSON_SCHEMA = _chunk34KLWUH4cjs.BRUSH_JSON_SCHEMA; exports.BRUSH_KINDS = _chunk34KLWUH4cjs.BRUSH_KINDS; exports.BRUSH_MARKS_KINDS = _chunk34KLWUH4cjs.BRUSH_MARKS_KINDS; exports.BRUSH_MEDIA = _chunk34KLWUH4cjs.BRUSH_MEDIA; exports.BRUSH_PATCH_PROPERTIES = _chunk34KLWUH4cjs.BRUSH_PATCH_PROPERTIES; exports.BRUSH_PRESETS = _chunk34KLWUH4cjs.BRUSH_PRESETS; exports.BRUSH_SURFACES = _chunk34KLWUH4cjs.BRUSH_SURFACES; exports.BRUSH_TIP_SHAPES = _chunk34KLWUH4cjs.BRUSH_TIP_SHAPES; exports.BRUSH_TOOLS = _chunk34KLWUH4cjs.BRUSH_TOOLS; exports.BRUSH_UNSET_PROPERTY = _chunk34KLWUH4cjs.BRUSH_UNSET_PROPERTY; exports.BRUSH_WORD = _chunk34KLWUH4cjs.BRUSH_WORD; exports.BrushLibraryError = _chunk34KLWUH4cjs.BrushLibraryError; exports.CANVAS_PROFILE = _chunk34KLWUH4cjs.CANVAS_PROFILE; exports.IMAGE_PROFILE = _chunk34KLWUH4cjs.IMAGE_PROFILE; exports.MAX_BRUSH_PALETTE = _chunk34KLWUH4cjs.MAX_BRUSH_PALETTE; exports.PAINT_PROFILE = _chunk34KLWUH4cjs.PAINT_PROFILE; exports.UNSETTABLE_BRUSH_FACETS = _chunk34KLWUH4cjs.UNSETTABLE_BRUSH_FACETS; exports.VECTOR_PROFILE = _chunk34KLWUH4cjs.VECTOR_PROFILE; exports.WET_BRUSH_TOOLS = _chunk34KLWUH4cjs.WET_BRUSH_TOOLS; exports.brushColourKind = _chunk34KLWUH4cjs.brushColourKind; exports.brushEditorSections = brushEditorSections; exports.brushLibraryGroups = brushLibraryGroups; exports.changedBrushPaths = _chunk34KLWUH4cjs.changedBrushPaths; exports.checkBrush = _chunk34KLWUH4cjs.checkBrush; exports.createBrushLibrary = _chunk34KLWUH4cjs.createBrushLibrary; exports.createBrushLibraryToolProvider = _chunk34KLWUH4cjs.createBrushLibraryToolProvider; exports.createBrushLibraryTools = _chunk34KLWUH4cjs.createBrushLibraryTools; exports.degrade = _chunk34KLWUH4cjs.degrade; exports.listPresets = _chunk34KLWUH4cjs.listPresets; exports.mergeBrushPatch = _chunk34KLWUH4cjs.mergeBrushPatch; exports.migrateBrushV1 = _chunk34KLWUH4cjs.migrateBrushV1; exports.normalizeBrushSpec = _chunk34KLWUH4cjs.normalizeBrushSpec; exports.parseBrushLibrary = _chunk34KLWUH4cjs.parseBrushLibrary; exports.resolveBrush = _chunk34KLWUH4cjs.resolveBrush; exports.resolveCategory = _chunk34KLWUH4cjs.resolveCategory; exports.resolveEngine = _chunk34KLWUH4cjs.resolveEngine; exports.resolveWetMedium = _chunk34KLWUH4cjs.resolveWetMedium; exports.setBrushEditorValue = setBrushEditorValue;
|