@pixerate/editor 0.281.0 → 0.282.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/animation-editor/index.cjs +59 -59
- package/dist/animation-editor/index.js +3 -3
- package/dist/brushes/index.cjs +76 -71
- package/dist/brushes/index.js +13 -8
- package/dist/brushes/schema.d.cts +1 -0
- package/dist/brushes/schema.d.ts +1 -0
- package/dist/brushes/types.d.cts +29 -3
- package/dist/brushes/types.d.ts +29 -3
- package/dist/{brushstrokeRender-EIK3625T.js → brushstrokeRender-4MA5CBW3.js} +3 -3
- package/dist/{brushstrokeRender-7HOMKZNO.cjs → brushstrokeRender-JVKVKWDA.cjs} +15 -15
- package/dist/canvas/index.cjs +13 -13
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-NJDEKU5D.js → chunk-2YGYYVSG.js} +1 -1
- package/dist/{chunk-JVFGK3DK.cjs → chunk-3JUKN3RM.cjs} +76 -53
- package/dist/{chunk-HN57I7KT.js → chunk-CG3FBNXE.js} +1 -1
- package/dist/{chunk-WFSYZO5Z.cjs → chunk-DFZ4I7EZ.cjs} +1 -1
- package/dist/{chunk-LZE2QZCT.js → chunk-IHMMHZGP.js} +1 -1
- package/dist/{chunk-K4ANWBF7.cjs → chunk-IJQ2YH2M.cjs} +35 -35
- package/dist/{chunk-HRUK5TFW.cjs → chunk-IUKPQCYQ.cjs} +164 -71
- package/dist/{chunk-WCC4NXWY.cjs → chunk-JD63B33V.cjs} +86 -86
- package/dist/{chunk-NJLPW4MM.js → chunk-KV7QHPKL.js} +27 -4
- package/dist/{chunk-H3EME3S5.cjs → chunk-MRIAR5DY.cjs} +2 -2
- package/dist/{chunk-ROURHJYT.js → chunk-NEDS6DSC.js} +1 -1
- package/dist/{chunk-FKO3CY2C.js → chunk-ULPXJ3NB.js} +1 -1
- package/dist/{chunk-WZYRYYXN.cjs → chunk-UOM5S4W5.cjs} +12 -12
- package/dist/{chunk-YOM76H2V.js → chunk-VEX6YVNG.js} +1 -1
- package/dist/{chunk-MNHP3AQT.cjs → chunk-WEXWDBUF.cjs} +23 -23
- package/dist/{chunk-PPDUCZZV.js → chunk-YRGTQLDN.js} +122 -29
- package/dist/image-editor/index.cjs +788 -788
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/antimatter.d.cts +154 -0
- package/dist/paint-editor/antimatter.d.ts +154 -0
- package/dist/paint-editor/brush-controls.d.cts +1 -0
- package/dist/paint-editor/brush-controls.d.ts +1 -0
- package/dist/paint-editor/brush-model.d.cts +9 -5
- package/dist/paint-editor/brush-model.d.ts +9 -5
- package/dist/paint-editor/controller.d.cts +23 -0
- package/dist/paint-editor/controller.d.ts +23 -0
- package/dist/paint-editor/index.cjs +1931 -891
- package/dist/paint-editor/index.d.cts +1 -0
- package/dist/paint-editor/index.d.ts +1 -0
- package/dist/paint-editor/index.js +1098 -58
- package/dist/paint-editor/mark-settings.d.cts +30 -0
- package/dist/paint-editor/mark-settings.d.ts +30 -0
- package/dist/paint-editor/stroke.d.cts +16 -0
- package/dist/paint-editor/stroke.d.ts +16 -0
- package/dist/paint-editor/strokes.d.cts +2 -0
- package/dist/paint-editor/strokes.d.ts +2 -0
- package/dist/paint-editor/ui.d.cts +4 -2
- package/dist/paint-editor/ui.d.ts +4 -2
- package/dist/vector/index.cjs +999 -999
- package/dist/vector/index.js +4 -4
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -1
- package/skills/pixerate-paint-editor/SKILL.md +8 -2
- package/skills/pixerate-paint-editor/references/antimatter.md +49 -0
- package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
|
@@ -955,11 +955,47 @@ var BRUSH_PRESETS = [
|
|
|
955
955
|
dynamics: { smoothing: 0.45, minSize: 0.25, velocitySize: -0.25 },
|
|
956
956
|
ferro: { amount: 0.7, wavelength: 12, threshold: 0.15 },
|
|
957
957
|
colour: { default: "#0f172a" }
|
|
958
|
+
},
|
|
959
|
+
// --- Antimatter paint: blasts that invert, scorch and destroy paint across visible layers ---
|
|
960
|
+
{
|
|
961
|
+
id: "antimatter",
|
|
962
|
+
name: "Antimatter",
|
|
963
|
+
kind: "mark",
|
|
964
|
+
medium: "paint",
|
|
965
|
+
variety: "antimatter",
|
|
966
|
+
tip: { shape: "round", size: 24, hardness: 0.75, spacing: 0.12 },
|
|
967
|
+
marks: { kind: "antimatter" },
|
|
968
|
+
dynamics: { smoothing: 0.25, minSize: 0.4 },
|
|
969
|
+
colour: { default: "#38bdf8", palette: ["#38bdf8", "#f472b6", "#a855f7", "#fb923c", "#4ade80"] }
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
id: "antimatter-flare",
|
|
973
|
+
name: "Antimatter flare",
|
|
974
|
+
kind: "mark",
|
|
975
|
+
medium: "paint",
|
|
976
|
+
variety: "antimatter",
|
|
977
|
+
tip: { shape: "round", size: 18, hardness: 0.7, spacing: 0.08 },
|
|
978
|
+
marks: { kind: "antimatter", blastRadius: 2, blastSpacing: 1.4, invert: 0.75, invertMode: "oklab", scorch: 0.35, annihilate: 0.15, sparks: 0.95, sparkReach: 5, crater: 0.3 },
|
|
979
|
+
dynamics: { smoothing: 0.2, minSize: 0.4 },
|
|
980
|
+
light: { amount: 0.9 },
|
|
981
|
+
colour: { default: "#f472b6", palette: ["#f472b6", "#38bdf8", "#facc15", "#a855f7", "#4ade80"] }
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
id: "antimatter-charge",
|
|
985
|
+
name: "Antimatter charge",
|
|
986
|
+
kind: "mark",
|
|
987
|
+
medium: "paint",
|
|
988
|
+
variety: "antimatter",
|
|
989
|
+
tip: { shape: "round", size: 32, hardness: 0.85, spacing: 0.15 },
|
|
990
|
+
marks: { kind: "antimatter", blastRadius: 4.5, blastSpacing: 4.5, threshold: 0.2, invertMode: "oklab", scorch: 0.8, annihilate: 0.6, sparks: 0.65, sparkReach: 4, crater: 0.85, duration: 1 },
|
|
991
|
+
dynamics: { smoothing: 0.3, minSize: 0.5 },
|
|
992
|
+
colour: { default: "#fb923c", palette: ["#fb923c", "#ef4444", "#38bdf8", "#a855f7"] }
|
|
958
993
|
}
|
|
959
994
|
];
|
|
960
995
|
|
|
961
996
|
// src/paint-editor/mark-settings.ts
|
|
962
997
|
var unit = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
998
|
+
var range = (v, lo, hi, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d;
|
|
963
999
|
var oneOf = (v, all, d) => all.includes(v) ? v : d;
|
|
964
1000
|
var MAX_STICKER_STAMPS = 16;
|
|
965
1001
|
var DEFAULT_STICKER = { stamps: ["editor:star"], density: 0.4, sizeJitter: 0.4, rotationJitter: 1, scatter: 0.5, colorJitter: 0.2 };
|
|
@@ -1051,9 +1087,38 @@ function normalizeBristle(raw = {}, base = DEFAULT_BRISTLE) {
|
|
|
1051
1087
|
jitter: unit(raw.jitter, base.jitter)
|
|
1052
1088
|
};
|
|
1053
1089
|
}
|
|
1090
|
+
var INVERT_MODES = ["rgb", "oklab"];
|
|
1091
|
+
var DEFAULT_ANTIMATTER = {
|
|
1092
|
+
blastRadius: 2.5,
|
|
1093
|
+
blastSpacing: 2,
|
|
1094
|
+
threshold: 0.1,
|
|
1095
|
+
invert: 1,
|
|
1096
|
+
invertMode: "rgb",
|
|
1097
|
+
scorch: 0.6,
|
|
1098
|
+
annihilate: 0.25,
|
|
1099
|
+
sparks: 0.5,
|
|
1100
|
+
sparkReach: 3,
|
|
1101
|
+
crater: 0.5,
|
|
1102
|
+
duration: 0.7
|
|
1103
|
+
};
|
|
1104
|
+
function normalizeAntimatter(raw = {}, base = DEFAULT_ANTIMATTER) {
|
|
1105
|
+
return {
|
|
1106
|
+
blastRadius: range(raw.blastRadius, 1, 6, base.blastRadius),
|
|
1107
|
+
blastSpacing: range(raw.blastSpacing, 0.5, 8, base.blastSpacing),
|
|
1108
|
+
threshold: unit(raw.threshold, base.threshold),
|
|
1109
|
+
invert: unit(raw.invert, base.invert),
|
|
1110
|
+
invertMode: oneOf(raw.invertMode, INVERT_MODES, base.invertMode),
|
|
1111
|
+
scorch: unit(raw.scorch, base.scorch),
|
|
1112
|
+
annihilate: unit(raw.annihilate, base.annihilate),
|
|
1113
|
+
sparks: unit(raw.sparks, base.sparks),
|
|
1114
|
+
sparkReach: range(raw.sparkReach, 0.5, 8, base.sparkReach),
|
|
1115
|
+
crater: unit(raw.crater, base.crater),
|
|
1116
|
+
duration: range(raw.duration, 0, 2, base.duration)
|
|
1117
|
+
};
|
|
1118
|
+
}
|
|
1054
1119
|
|
|
1055
1120
|
// src/paint-editor/brush-model.ts
|
|
1056
|
-
var PAINT_BRUSH_ENGINES = ["dab", "eraser", "mixer", "blender", "smudge", "wet", "impasto", "particle", "bristle", "sticker"];
|
|
1121
|
+
var PAINT_BRUSH_ENGINES = ["dab", "eraser", "mixer", "blender", "smudge", "wet", "impasto", "particle", "bristle", "sticker", "antimatter"];
|
|
1057
1122
|
var PAINT_BRUSH_CATEGORIES = ["pencil", "pastel", "charcoal", "airbrush", "marker", "ink", "paint", "eraser", "blender", "smudge", "mixer", "watercolor", "wet-tool", "oil", "impasto", "procedural", "bristle", "sticker", "light", "custom"];
|
|
1058
1123
|
var WET_TOOLS = ["paint", "water", "dry", "blow", "blend", "smudge", "blot"];
|
|
1059
1124
|
var WET_MEDIA = ["watercolor", "gouache", "oil"];
|
|
@@ -1090,7 +1155,7 @@ function normalizeThermochromic(raw = {}, base = DEFAULT_THERMOCHROMIC) {
|
|
|
1090
1155
|
const hotColor = raw.hotColor === null ? null : typeof raw.hotColor === "string" && HEX.test(raw.hotColor.trim()) ? raw.hotColor.trim().toLowerCase() : base.hotColor;
|
|
1091
1156
|
return {
|
|
1092
1157
|
hotColor,
|
|
1093
|
-
threshold:
|
|
1158
|
+
threshold: range2(raw.threshold, 0.05, 0.95, base.threshold)
|
|
1094
1159
|
};
|
|
1095
1160
|
}
|
|
1096
1161
|
var DEFAULT_IRIDESCENCE = { thickness: 400, pressureToThickness: 0, ior: 1.5 };
|
|
@@ -1101,9 +1166,9 @@ function readIridescence(raw, base) {
|
|
|
1101
1166
|
const r = raw;
|
|
1102
1167
|
const b = _nullishCoalesce(base, () => ( DEFAULT_IRIDESCENCE));
|
|
1103
1168
|
return {
|
|
1104
|
-
thickness:
|
|
1169
|
+
thickness: range2(r.thickness, 100, 1e3, b.thickness),
|
|
1105
1170
|
pressureToThickness: unit2(r.pressureToThickness, b.pressureToThickness),
|
|
1106
|
-
ior:
|
|
1171
|
+
ior: range2(r.ior, 1.2, 2, b.ior)
|
|
1107
1172
|
};
|
|
1108
1173
|
}
|
|
1109
1174
|
var GHOST_TRIGGERS = ["immediate", "agent"];
|
|
@@ -1111,7 +1176,7 @@ var DEFAULT_GHOST = { linger: 4, smear: 0.3 };
|
|
|
1111
1176
|
function normalizeGhost(raw = {}, base = DEFAULT_GHOST) {
|
|
1112
1177
|
const trigger = raw.trigger === "agent" || raw.trigger === "immediate" ? raw.trigger : base.trigger;
|
|
1113
1178
|
return {
|
|
1114
|
-
linger:
|
|
1179
|
+
linger: range2(raw.linger, 0.5, 60, base.linger),
|
|
1115
1180
|
smear: unit2(raw.smear, base.smear),
|
|
1116
1181
|
...trigger === "agent" ? { trigger: "agent" } : {}
|
|
1117
1182
|
};
|
|
@@ -1119,9 +1184,9 @@ function normalizeGhost(raw = {}, base = DEFAULT_GHOST) {
|
|
|
1119
1184
|
var DEFAULT_MUTATION = { settle: 1.5, patience: 45, fade: 2 };
|
|
1120
1185
|
function normalizeMutation(raw = {}, base = DEFAULT_MUTATION) {
|
|
1121
1186
|
return {
|
|
1122
|
-
settle:
|
|
1123
|
-
patience:
|
|
1124
|
-
fade:
|
|
1187
|
+
settle: range2(raw.settle, 0.5, 10, base.settle),
|
|
1188
|
+
patience: range2(raw.patience, 5, 300, base.patience),
|
|
1189
|
+
fade: range2(raw.fade, 0.5, 10, base.fade)
|
|
1125
1190
|
};
|
|
1126
1191
|
}
|
|
1127
1192
|
var DEFAULT_FERRO = { amount: 0, wavelength: 16, threshold: 0.12 };
|
|
@@ -1132,8 +1197,8 @@ function normalizeFerro(raw = {}, base = DEFAULT_FERRO) {
|
|
|
1132
1197
|
const r = _nullishCoalesce(raw, () => ( {}));
|
|
1133
1198
|
return {
|
|
1134
1199
|
amount: unit2(r.amount, base.amount),
|
|
1135
|
-
wavelength:
|
|
1136
|
-
threshold:
|
|
1200
|
+
wavelength: range2(r.wavelength, 4, 64, base.wavelength),
|
|
1201
|
+
threshold: range2(r.threshold, 0.01, 0.95, base.threshold)
|
|
1137
1202
|
};
|
|
1138
1203
|
}
|
|
1139
1204
|
function normalizeImpasto(raw = {}, base = DEFAULT_IMPASTO) {
|
|
@@ -1170,7 +1235,7 @@ var DEFAULT_DYNAMICS = {
|
|
|
1170
1235
|
scatter: 0
|
|
1171
1236
|
};
|
|
1172
1237
|
var unit2 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
1173
|
-
var
|
|
1238
|
+
var range2 = (v, lo, hi, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(hi, Math.max(lo, v)) : d;
|
|
1174
1239
|
function normalizeDynamics(raw = {}, base = DEFAULT_DYNAMICS) {
|
|
1175
1240
|
return {
|
|
1176
1241
|
minSize: unit2(raw.minSize, base.minSize),
|
|
@@ -1178,12 +1243,12 @@ function normalizeDynamics(raw = {}, base = DEFAULT_DYNAMICS) {
|
|
|
1178
1243
|
tiltSize: unit2(raw.tiltSize, base.tiltSize),
|
|
1179
1244
|
tiltRoundness: unit2(raw.tiltRoundness, base.tiltRoundness),
|
|
1180
1245
|
tiltOpacity: unit2(raw.tiltOpacity, base.tiltOpacity),
|
|
1181
|
-
velocitySize:
|
|
1182
|
-
velocityOpacity:
|
|
1246
|
+
velocitySize: range2(raw.velocitySize, -1, 1, base.velocitySize),
|
|
1247
|
+
velocityOpacity: range2(raw.velocityOpacity, -1, 1, base.velocityOpacity),
|
|
1183
1248
|
sizeJitter: unit2(raw.sizeJitter, base.sizeJitter),
|
|
1184
1249
|
angleJitter: unit2(raw.angleJitter, base.angleJitter),
|
|
1185
1250
|
opacityJitter: unit2(raw.opacityJitter, base.opacityJitter),
|
|
1186
|
-
scatter:
|
|
1251
|
+
scatter: range2(raw.scatter, 0, 4, base.scatter),
|
|
1187
1252
|
...countAndFlip(raw, base)
|
|
1188
1253
|
};
|
|
1189
1254
|
}
|
|
@@ -1230,9 +1295,9 @@ function readTipGrain(raw, base) {
|
|
|
1230
1295
|
return {
|
|
1231
1296
|
source,
|
|
1232
1297
|
mode: TIP_GRAIN_MODES.includes(r.mode) ? r.mode : b.mode,
|
|
1233
|
-
scale:
|
|
1298
|
+
scale: range2(r.scale, 0.05, 20, b.scale),
|
|
1234
1299
|
depth: unit2(r.depth, b.depth),
|
|
1235
|
-
contrast:
|
|
1300
|
+
contrast: range2(r.contrast, 0, 3, b.contrast),
|
|
1236
1301
|
invert: typeof r.invert === "boolean" ? r.invert : b.invert
|
|
1237
1302
|
};
|
|
1238
1303
|
}
|
|
@@ -1248,7 +1313,7 @@ function readSpray(raw, base) {
|
|
|
1248
1313
|
if (!raw || typeof raw !== "object") return base;
|
|
1249
1314
|
const r = raw;
|
|
1250
1315
|
const b = _nullishCoalesce(base, () => ( DEFAULT_SPRAY));
|
|
1251
|
-
return { density: unit2(r.density, b.density), size:
|
|
1316
|
+
return { density: unit2(r.density, b.density), size: range2(r.size, 0.02, 1, b.size) };
|
|
1252
1317
|
}
|
|
1253
1318
|
function isWetCapable(brush) {
|
|
1254
1319
|
return brush.engine === "dab" || brush.engine === "mixer" || brush.engine === "wet" || brush.engine === "impasto";
|
|
@@ -1345,7 +1410,7 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1345
1410
|
engine,
|
|
1346
1411
|
tip: _chunkIFWLZZCWcjs.normalizeBrush.call(void 0, { ...b.tip, ..._nullishCoalesce(raw.tip, () => ( {})) }),
|
|
1347
1412
|
grain: unit2(raw.grain, b.grain),
|
|
1348
|
-
pressureSmoothing:
|
|
1413
|
+
pressureSmoothing: range2(raw.pressureSmoothing, 0, 0.95, b.pressureSmoothing),
|
|
1349
1414
|
rotation: BRUSH_ROTATIONS.includes(raw.rotation) ? raw.rotation : b.rotation,
|
|
1350
1415
|
dynamics: normalizeDynamics(_nullishCoalesce(raw.dynamics, () => ( {})), b.dynamics),
|
|
1351
1416
|
mixer,
|
|
@@ -1358,6 +1423,7 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1358
1423
|
particle: normalizeParticle(_nullishCoalesce(raw.particle, () => ( {})), _nullishCoalesce(b.particle, () => ( DEFAULT_PARTICLE))),
|
|
1359
1424
|
bristle: normalizeBristle(_nullishCoalesce(raw.bristle, () => ( {})), _nullishCoalesce(b.bristle, () => ( DEFAULT_BRISTLE))),
|
|
1360
1425
|
sticker: normalizeStickerSettings(_nullishCoalesce(raw.sticker, () => ( {})), _nullishCoalesce(b.sticker, () => ( DEFAULT_STICKER))),
|
|
1426
|
+
antimatter: normalizeAntimatter(_nullishCoalesce(raw.antimatter, () => ( {})), _nullishCoalesce(b.antimatter, () => ( DEFAULT_ANTIMATTER))),
|
|
1361
1427
|
light: ghost && !wantsLight ? { ...DEFAULT_LIGHT } : normalizeLight(_nullishCoalesce(raw.light, () => ( {})), _nullishCoalesce(b.light, () => ( DEFAULT_LIGHT))),
|
|
1362
1428
|
fluorescence: normalizeFluorescence(_nullishCoalesce(raw.fluorescence, () => ( {})), _nullishCoalesce(b.fluorescence, () => ( DEFAULT_FLUORESCENCE))),
|
|
1363
1429
|
thermochromic: normalizeThermochromic(_nullishCoalesce(raw.thermochromic, () => ( {})), _nullishCoalesce(b.thermochromic, () => ( DEFAULT_THERMOCHROMIC))),
|
|
@@ -1393,6 +1459,7 @@ var BASE_BRUSH = {
|
|
|
1393
1459
|
particle: { ...DEFAULT_PARTICLE },
|
|
1394
1460
|
bristle: { ...DEFAULT_BRISTLE },
|
|
1395
1461
|
sticker: { ...DEFAULT_STICKER, stamps: [...DEFAULT_STICKER.stamps] },
|
|
1462
|
+
antimatter: { ...DEFAULT_ANTIMATTER },
|
|
1396
1463
|
light: { ...DEFAULT_LIGHT },
|
|
1397
1464
|
fluorescence: { ...DEFAULT_FLUORESCENCE },
|
|
1398
1465
|
thermochromic: { ...DEFAULT_THERMOCHROMIC },
|
|
@@ -1403,7 +1470,7 @@ var BASE_BRUSH = {
|
|
|
1403
1470
|
};
|
|
1404
1471
|
|
|
1405
1472
|
// src/brushes/resolve.ts
|
|
1406
|
-
var ALL = ["dab", "eraser", "mixer", "blender", "smudge", "wet", "impasto", "particle", "bristle", "sticker"];
|
|
1473
|
+
var ALL = ["dab", "eraser", "mixer", "blender", "smudge", "wet", "impasto", "particle", "bristle", "sticker", "antimatter"];
|
|
1407
1474
|
var EXCHANGE = ["dab", "wet", "impasto"];
|
|
1408
1475
|
var DABS = ["dab", "eraser", "mixer", "blender", "smudge"];
|
|
1409
1476
|
var FILM = ["dab", "mixer", "wet", "impasto", "particle", "bristle"];
|
|
@@ -1497,6 +1564,7 @@ var BRUSH_FIELDS = [
|
|
|
1497
1564
|
f("marks.size", "spray.size", ["dab"], { marks: ["scatter"] }),
|
|
1498
1565
|
...each("marks", "sticker", ["density", "sizeJitter", "rotationJitter", "scatter"], ["sticker"]),
|
|
1499
1566
|
f("marks.colourJitter", "sticker.colorJitter", ["sticker"]),
|
|
1567
|
+
...each("marks", "antimatter", ["blastRadius", "blastSpacing", "threshold", "invert", "invertMode", "scorch", "annihilate", "sparks", "sparkReach", "crater", "duration"], ["antimatter"]),
|
|
1500
1568
|
...each("tip.bristle", "bristle", ["count", "stiffness", "splay", "thickness", "load", "jitter"], ["bristle"])
|
|
1501
1569
|
];
|
|
1502
1570
|
var WET_TOOL_OF = { water: "water", dryer: "dry", blow: "blow", blot: "blot", "wet-blend": "blend", "wet-drag": "smudge" };
|
|
@@ -1520,13 +1588,14 @@ function setPath(o, path, value) {
|
|
|
1520
1588
|
var copy = (v) => v !== null && typeof v === "object" ? JSON.parse(JSON.stringify(v)) : v;
|
|
1521
1589
|
function resolveEngine(brush) {
|
|
1522
1590
|
if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet";
|
|
1523
|
-
if (_optionalChain([brush, 'access', _5 => _5.marks, 'optionalAccess', _6 => _6.kind]) === "
|
|
1524
|
-
if (_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]) === "
|
|
1591
|
+
if (_optionalChain([brush, 'access', _5 => _5.marks, 'optionalAccess', _6 => _6.kind]) === "antimatter") return "antimatter";
|
|
1592
|
+
if (_optionalChain([brush, 'access', _7 => _7.marks, 'optionalAccess', _8 => _8.kind]) === "particles") return "particle";
|
|
1593
|
+
if (_optionalChain([brush, 'access', _9 => _9.marks, 'optionalAccess', _10 => _10.kind]) === "objects") return "sticker";
|
|
1525
1594
|
if (brush.tip.shape === "bristle") return "bristle";
|
|
1526
|
-
const surface = _optionalChain([brush, 'access',
|
|
1595
|
+
const surface = _optionalChain([brush, 'access', _11 => _11.behaviour, 'optionalAccess', _12 => _12.surface]);
|
|
1527
1596
|
if (surface === "thick") return "impasto";
|
|
1528
1597
|
if (surface === "wet") return "wet";
|
|
1529
|
-
if (_optionalChain([brush, 'access',
|
|
1598
|
+
if (_optionalChain([brush, 'access', _13 => _13.behaviour, 'optionalAccess', _14 => _14.exchange, 'optionalAccess', _15 => _15.reservoir])) return "mixer";
|
|
1530
1599
|
return "dab";
|
|
1531
1600
|
}
|
|
1532
1601
|
var VARIETY_CATEGORY = {
|
|
@@ -1542,11 +1611,11 @@ var VARIETY_CATEGORY = {
|
|
|
1542
1611
|
};
|
|
1543
1612
|
var MEDIUM_CATEGORY = { paint: "paint", ink: "ink", dry: "pencil", spray: "airbrush" };
|
|
1544
1613
|
function resolveWetMedium(brush) {
|
|
1545
|
-
return _nullishCoalesce(_optionalChain([brush, 'access',
|
|
1614
|
+
return _nullishCoalesce(_optionalChain([brush, 'access', _16 => _16.behaviour, 'optionalAccess', _17 => _17.wet, 'optionalAccess', _18 => _18.medium]), () => ( (WET_MEDIA.includes(brush.variety) ? brush.variety : void 0)));
|
|
1546
1615
|
}
|
|
1547
1616
|
function resolveCategory(brush, engine = resolveEngine(brush)) {
|
|
1548
1617
|
if (brush.kind === "tool") return brush.tool === "eraser" || brush.tool === "blender" || brush.tool === "smudge" ? brush.tool : "wet-tool";
|
|
1549
|
-
if ((_nullishCoalesce(_optionalChain([brush, 'access',
|
|
1618
|
+
if ((_nullishCoalesce(_optionalChain([brush, 'access', _19 => _19.light, 'optionalAccess', _20 => _20.amount]), () => ( 0))) > 0) return "light";
|
|
1550
1619
|
switch (engine) {
|
|
1551
1620
|
case "particle":
|
|
1552
1621
|
return "procedural";
|
|
@@ -1568,11 +1637,11 @@ function resolveBrush(brush, options = {}) {
|
|
|
1568
1637
|
const engine = resolveEngine(brush);
|
|
1569
1638
|
const input = { id: brush.id, name: brush.name, category: resolveCategory(brush, engine), engine };
|
|
1570
1639
|
for (const field of BRUSH_FIELDS) {
|
|
1571
|
-
if (!field.engines.includes(engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access',
|
|
1640
|
+
if (!field.engines.includes(engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _21 => _21.marks, 'optionalAccess', _22 => _22.kind]), () => ( "continuous")))) continue;
|
|
1572
1641
|
const v = getPath(brush, field.facet);
|
|
1573
1642
|
if (v !== void 0) setPath(input, field.engine, field.map ? field.map.toEngine(v) : copy(v));
|
|
1574
1643
|
}
|
|
1575
|
-
if (engine === "dab" && _optionalChain([brush, 'access',
|
|
1644
|
+
if (engine === "dab" && _optionalChain([brush, 'access', _23 => _23.marks, 'optionalAccess', _24 => _24.kind]) === "scatter") input.spray = { ..._nullishCoalesce(input.spray, () => ( {})) };
|
|
1576
1645
|
if (brush.iridescence && FILM.includes(engine)) input.iridescence = { ..._nullishCoalesce(input.iridescence, () => ( {})) };
|
|
1577
1646
|
if (engine === "wet") {
|
|
1578
1647
|
setPath(input, "wet.tool", brush.kind === "tool" ? WET_TOOL_OF[brush.tool] : "paint");
|
|
@@ -1583,7 +1652,7 @@ function resolveBrush(brush, options = {}) {
|
|
|
1583
1652
|
}
|
|
1584
1653
|
if (brush.kind !== "tool" && brush.mutation) input.mutation = { ..._nullishCoalesce(input.mutation, () => ( {})) };
|
|
1585
1654
|
if (engine === "blender" || engine === "smudge") input.loadsColor = false;
|
|
1586
|
-
const paint = _optionalChain([brush, 'access',
|
|
1655
|
+
const paint = _optionalChain([brush, 'access', _25 => _25.colour, 'optionalAccess', _26 => _26.default]);
|
|
1587
1656
|
if (paint && typeof paint === "object" && "type" in paint && paint.type === "gradient") input.paint = copy(paint);
|
|
1588
1657
|
return normalizePaintBrush({ ...input, ...options.builtin ? { builtin: true } : {} });
|
|
1589
1658
|
}
|
|
@@ -1657,6 +1726,8 @@ function skeleton(b) {
|
|
|
1657
1726
|
return { ...brush, medium: "paint", ...mut };
|
|
1658
1727
|
case "particle":
|
|
1659
1728
|
return { ...brush, marks: { kind: "particles" }, ...mut };
|
|
1729
|
+
case "antimatter":
|
|
1730
|
+
return { ...brush, medium: "paint", marks: { kind: "antimatter" }, ...mut };
|
|
1660
1731
|
case "sticker":
|
|
1661
1732
|
return { id: b.id, name: b.name, kind: "mark", tip: { shape: tipShape(b) }, marks: { kind: "objects" }, ...mut };
|
|
1662
1733
|
default: {
|
|
@@ -1671,7 +1742,7 @@ function migrateBrushV1(raw) {
|
|
|
1671
1742
|
const brush = skeleton(b);
|
|
1672
1743
|
const defaults = resolveBrush(brush);
|
|
1673
1744
|
for (const field of BRUSH_FIELDS) {
|
|
1674
|
-
if (!field.engines.includes(b.engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access',
|
|
1745
|
+
if (!field.engines.includes(b.engine) || field.shapes && !field.shapes.includes(brush.tip.shape) || field.marks && !field.marks.includes(_nullishCoalesce(_optionalChain([brush, 'access', _27 => _27.marks, 'optionalAccess', _28 => _28.kind]), () => ( "continuous")))) continue;
|
|
1675
1746
|
const v = getPath(b, field.engine);
|
|
1676
1747
|
if (!equal(v, getPath(defaults, field.engine))) setPath(brush, field.facet, field.map ? field.map.toFacet(v) : copy2(v));
|
|
1677
1748
|
}
|
|
@@ -1684,7 +1755,7 @@ var BRUSH_KINDS = ["mark", "tool"];
|
|
|
1684
1755
|
var BRUSH_MEDIA = ["paint", "ink", "dry", "spray"];
|
|
1685
1756
|
var BRUSH_TOOLS = ["eraser", "blender", "smudge", "water", "dryer", "blow", "blot", "wet-blend", "wet-drag"];
|
|
1686
1757
|
var BRUSH_TIP_SHAPES = ["round", "flat", "chisel", "bristle", "stamp"];
|
|
1687
|
-
var BRUSH_MARKS_KINDS = ["continuous", "scatter", "particles", "objects"];
|
|
1758
|
+
var BRUSH_MARKS_KINDS = ["continuous", "scatter", "particles", "objects", "antimatter"];
|
|
1688
1759
|
var BRUSH_SURFACES = ["dry", "wet", "thick"];
|
|
1689
1760
|
var BRUSH_GRAIN_MODES = ["moving", "texturised"];
|
|
1690
1761
|
var BRUSH_FLIPS = ["none", "x", "y", "xy"];
|
|
@@ -1811,6 +1882,24 @@ var OBJECTS = object(
|
|
|
1811
1882
|
},
|
|
1812
1883
|
["kind"]
|
|
1813
1884
|
);
|
|
1885
|
+
var ANTIMATTER = object(
|
|
1886
|
+
"Antimatter paint: where the tip touches paint across any visible layer, it detonates \u2014 inverting colours in the core, removing alpha, burning a soot ring, denting thick relief, clearing core light, and throwing sparks on the active layer. Missing fields take their defaults.",
|
|
1887
|
+
{
|
|
1888
|
+
kind: { type: "string", const: "antimatter", description: 'Always "antimatter".' },
|
|
1889
|
+
blastRadius: num(1, 6, "Blast size, in tip radii (default 2.5)."),
|
|
1890
|
+
blastSpacing: num(0.5, 8, "Stroke travel between blasts, in tip diameters (default 2)."),
|
|
1891
|
+
threshold: unit3("Paint needed under the tip to fire (default 0.1)."),
|
|
1892
|
+
invert: unit3("Strength of the colour inversion in the blast core (default 1)."),
|
|
1893
|
+
invertMode: oneOf2(INVERT_MODES, "Colour inversion mode: rgb (default, channel complement) or oklab (flips lightness and hue so mid-grey changes too)."),
|
|
1894
|
+
scorch: unit3("Strength of the soot ring around the blast (default 0.6)."),
|
|
1895
|
+
annihilate: unit3("Paint destroyed at the centre \u2014 alpha removed, unless the layer has lockTransparency (default 0.25)."),
|
|
1896
|
+
sparks: unit3("How many sparks fly out from each blast on the active layer (default 0.5; 0: none)."),
|
|
1897
|
+
sparkReach: num(0.5, 8, "How far sparks fly, in tip diameters (default 3)."),
|
|
1898
|
+
crater: unit3("Depth of the crater dent and raised rim on layers with thick relief (default 0.5)."),
|
|
1899
|
+
duration: num(0, 2, "Seconds a blast plays on screen (default 0.7; 0 shows the result at once).")
|
|
1900
|
+
},
|
|
1901
|
+
["kind"]
|
|
1902
|
+
);
|
|
1814
1903
|
var DYNAMICS = object("Pen feel: pressure, tilt, velocity, jitter, rotation and smoothing. Every amount 0 (off) .. 1 unless noted; missing fields take their defaults.", {
|
|
1815
1904
|
pressureSize: bool("Pressure scales the size, down to minSize (default true)."),
|
|
1816
1905
|
pressureOpacity: bool("Pressure scales the opacity (default false)."),
|
|
@@ -1981,7 +2070,7 @@ var BRUSH_JSON_SCHEMA = object(
|
|
|
1981
2070
|
"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."
|
|
1982
2071
|
),
|
|
1983
2072
|
tip: TIP,
|
|
1984
|
-
marks: { description: "How the tip is laid along the path (default continuous): continuous dabs, a scatter of spray droplets, particles,
|
|
2073
|
+
marks: { description: "How the tip is laid along the path (default continuous): continuous dabs, a scatter of spray droplets, particles, objects (editable stickers), or antimatter (detonations that invert, scorch and destroy paint across every visible layer).", oneOf: [CONTINUOUS, SCATTER, PARTICLES, OBJECTS, ANTIMATTER] },
|
|
1985
2074
|
dynamics: DYNAMICS,
|
|
1986
2075
|
behaviour: BEHAVIOUR,
|
|
1987
2076
|
light: LIGHT,
|
|
@@ -2000,7 +2089,7 @@ var BRUSH_JSON_SCHEMA = object(
|
|
|
2000
2089
|
var BRUSH_FACET_SCHEMAS = {
|
|
2001
2090
|
tip: TIP,
|
|
2002
2091
|
tipGrain: TIP_GRAIN,
|
|
2003
|
-
marks: { continuous: CONTINUOUS, scatter: SCATTER, particles: PARTICLES, objects: OBJECTS },
|
|
2092
|
+
marks: { continuous: CONTINUOUS, scatter: SCATTER, particles: PARTICLES, objects: OBJECTS, antimatter: ANTIMATTER },
|
|
2004
2093
|
dynamics: DYNAMICS,
|
|
2005
2094
|
behaviour: BEHAVIOUR,
|
|
2006
2095
|
light: LIGHT,
|
|
@@ -2219,7 +2308,7 @@ function readObject(value, schema, path, problems) {
|
|
|
2219
2308
|
const out = {};
|
|
2220
2309
|
for (const [key, v] of Object.entries(value)) {
|
|
2221
2310
|
if (v === void 0) continue;
|
|
2222
|
-
const child = _optionalChain([schema, 'access',
|
|
2311
|
+
const child = _optionalChain([schema, 'access', _29 => _29.properties, 'optionalAccess', _30 => _30[key]]);
|
|
2223
2312
|
if (!child) {
|
|
2224
2313
|
problems.push(`${path}.${key} is not a brush field; dropped.`);
|
|
2225
2314
|
continue;
|
|
@@ -2258,7 +2347,7 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2258
2347
|
const { colour: rawColour, marks: rawMarks, ferro: rawFerro, kind: _k, id: _i, name: _n, tool: _t, ...rest } = raw;
|
|
2259
2348
|
if (typeof rest.fluorescence === "number" && Number.isFinite(rest.fluorescence)) rest.fluorescence = { amount: rest.fluorescence };
|
|
2260
2349
|
const out = readObject(rest, BRUSH_JSON_SCHEMA, "brush", problems);
|
|
2261
|
-
if (_optionalChain([out, 'access',
|
|
2350
|
+
if (_optionalChain([out, 'access', _31 => _31.thermochromic, 'optionalAccess', _32 => _32.hotColor])) out.thermochromic.hotColor = out.thermochromic.hotColor.toLowerCase();
|
|
2262
2351
|
const brush = { id: raw.id, name, ...out, kind, ...tool ? { tool } : {}, tip: _nullishCoalesce(out.tip, () => ( { shape: "round" })) };
|
|
2263
2352
|
const ordered = () => {
|
|
2264
2353
|
const { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, fluorescence, thermochromic, iridescence, ghost, mutation, ferro, motion, livePatterns, colour } = brush;
|
|
@@ -2273,7 +2362,7 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2273
2362
|
if (rawMarks !== void 0) {
|
|
2274
2363
|
const k = isObject(rawMarks) ? rawMarks.kind : void 0;
|
|
2275
2364
|
const schema = BRUSH_FACET_SCHEMAS.marks[k];
|
|
2276
|
-
if (!schema) problems.push(`marks.kind ${JSON.stringify(k)} is not valid; use continuous, scatter, particles or
|
|
2365
|
+
if (!schema) problems.push(`marks.kind ${JSON.stringify(k)} is not valid; use continuous, scatter, particles, objects or antimatter. marks dropped.`);
|
|
2277
2366
|
else brush.marks = readObject(rawMarks, schema, "brush.marks", problems);
|
|
2278
2367
|
}
|
|
2279
2368
|
if (rawFerro !== void 0) {
|
|
@@ -2324,19 +2413,19 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2324
2413
|
delete brush.iridescence;
|
|
2325
2414
|
}
|
|
2326
2415
|
}
|
|
2327
|
-
if (brush.iridescence && _optionalChain([brush, 'access',
|
|
2328
|
-
drop("iridescence", "object marks are stickers, not film");
|
|
2416
|
+
if (brush.iridescence && (_optionalChain([brush, 'access', _33 => _33.marks, 'optionalAccess', _34 => _34.kind]) === "objects" || _optionalChain([brush, 'access', _35 => _35.marks, 'optionalAccess', _36 => _36.kind]) === "antimatter")) {
|
|
2417
|
+
drop("iridescence", brush.marks.kind === "antimatter" ? "antimatter marks detonate paint, not film" : "object marks are stickers, not film");
|
|
2329
2418
|
delete brush.iridescence;
|
|
2330
2419
|
}
|
|
2331
|
-
if (_optionalChain([brush, 'access',
|
|
2332
|
-
const surface = _optionalChain([brush, 'access',
|
|
2333
|
-
const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access',
|
|
2420
|
+
if (_optionalChain([brush, 'access', _37 => _37.marks, 'optionalAccess', _38 => _38.kind]) === "scatter") {
|
|
2421
|
+
const surface = _optionalChain([brush, 'access', _39 => _39.behaviour, 'optionalAccess', _40 => _40.surface]);
|
|
2422
|
+
const why = brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : surface === "wet" || surface === "thick" ? `${surface} paint is not sprayed` : _optionalChain([brush, 'access', _41 => _41.behaviour, 'optionalAccess', _42 => _42.exchange, 'optionalAccess', _43 => _43.reservoir]) ? "the Mixer Brush is not sprayed" : null;
|
|
2334
2423
|
if (why) {
|
|
2335
2424
|
drop("marks", why);
|
|
2336
2425
|
delete brush.marks;
|
|
2337
2426
|
}
|
|
2338
2427
|
}
|
|
2339
|
-
if (_optionalChain([brush, 'access',
|
|
2428
|
+
if (_optionalChain([brush, 'access', _44 => _44.marks, 'optionalAccess', _45 => _45.kind]) === "objects" && brush.tip.shape !== "stamp") {
|
|
2340
2429
|
problems.push("marks objects lay stamps: tip.shape set to stamp.");
|
|
2341
2430
|
brush.tip.shape = "stamp";
|
|
2342
2431
|
}
|
|
@@ -2350,7 +2439,7 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2350
2439
|
}
|
|
2351
2440
|
if (brush.tip.stamps) {
|
|
2352
2441
|
let stamps = brush.tip.stamps.map((s) => _chunkRDFHWAHLcjs.normalizeStickerRef.call(void 0, s));
|
|
2353
|
-
if (_optionalChain([brush, 'access',
|
|
2442
|
+
if (_optionalChain([brush, 'access', _46 => _46.marks, 'optionalAccess', _47 => _47.kind]) === "objects" && stamps.some(isBrushSourceRef)) {
|
|
2354
2443
|
problems.push("tip.stamps: image sources (source:\u2026) dropped: objects marks lay stickers; use continuous, scatter or particles marks for an image tip.");
|
|
2355
2444
|
stamps = stamps.filter((s) => !isBrushSourceRef(s));
|
|
2356
2445
|
}
|
|
@@ -2361,9 +2450,9 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2361
2450
|
}
|
|
2362
2451
|
}
|
|
2363
2452
|
if (brush.tip.grain) {
|
|
2364
|
-
const surface = _optionalChain([brush, 'access',
|
|
2365
|
-
const marks = _optionalChain([brush, 'access',
|
|
2366
|
-
const why = !brush.tip.grain.source ? "it needs a source (a grain pattern or source:<id>)" : brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : marks === "particles" || marks === "objects" ? `${marks} marks are not dabs` : surface === "wet" || surface === "thick" ? `${surface} paint lays its own texture` : kind === "tool" && WET_BRUSH_TOOLS.includes(brush.tool) ? "the wet tools work on the wet layer" : null;
|
|
2453
|
+
const surface = _optionalChain([brush, 'access', _48 => _48.behaviour, 'optionalAccess', _49 => _49.surface]);
|
|
2454
|
+
const marks = _optionalChain([brush, 'access', _50 => _50.marks, 'optionalAccess', _51 => _51.kind]);
|
|
2455
|
+
const why = !brush.tip.grain.source ? "it needs a source (a grain pattern or source:<id>)" : brush.tip.shape === "bristle" ? "bristle tips lay their own marks" : marks === "particles" || marks === "objects" || marks === "antimatter" ? `${marks} marks are not dabs` : surface === "wet" || surface === "thick" ? `${surface} paint lays its own texture` : kind === "tool" && WET_BRUSH_TOOLS.includes(brush.tool) ? "the wet tools work on the wet layer" : null;
|
|
2367
2456
|
if (why) {
|
|
2368
2457
|
drop("tip.grain", why);
|
|
2369
2458
|
delete brush.tip.grain;
|
|
@@ -2399,17 +2488,17 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2399
2488
|
if (b.exchange && kind === "tool" && !wetTool) {
|
|
2400
2489
|
drop("behaviour.exchange", `the ${brush.tool} does not pick paint up`);
|
|
2401
2490
|
delete b.exchange;
|
|
2402
|
-
} else if (b.exchange && (_optionalChain([brush, 'access',
|
|
2403
|
-
drop("behaviour.exchange", "particle, object and bristle marks do not pick paint up");
|
|
2491
|
+
} else if (b.exchange && (_optionalChain([brush, 'access', _52 => _52.marks, 'optionalAccess', _53 => _53.kind]) === "particles" || _optionalChain([brush, 'access', _54 => _54.marks, 'optionalAccess', _55 => _55.kind]) === "objects" || _optionalChain([brush, 'access', _56 => _56.marks, 'optionalAccess', _57 => _57.kind]) === "antimatter" || brush.tip.shape === "bristle")) {
|
|
2492
|
+
drop("behaviour.exchange", "particle, object, antimatter and bristle marks do not pick paint up");
|
|
2404
2493
|
delete b.exchange;
|
|
2405
2494
|
}
|
|
2406
2495
|
}
|
|
2407
|
-
if (brush.livePatterns && (kind !== "mark" || _optionalChain([brush, 'access',
|
|
2496
|
+
if (brush.livePatterns && (kind !== "mark" || _optionalChain([brush, 'access', _58 => _58.behaviour, 'optionalAccess', _59 => _59.surface]) !== "wet" || _optionalChain([brush, 'access', _60 => _60.marks, 'optionalAccess', _61 => _61.kind]) === "particles" || _optionalChain([brush, 'access', _62 => _62.marks, 'optionalAccess', _63 => _63.kind]) === "objects" || _optionalChain([brush, 'access', _64 => _64.marks, 'optionalAccess', _65 => _65.kind]) === "antimatter" || brush.tip.shape === "bristle")) {
|
|
2408
2497
|
drop("livePatterns", "only wet paint brushes grow live patterns (set behaviour.surface to wet)");
|
|
2409
2498
|
delete brush.livePatterns;
|
|
2410
2499
|
}
|
|
2411
2500
|
if (brush.ghost) {
|
|
2412
|
-
if (kind === "tool" || _optionalChain([brush, 'access',
|
|
2501
|
+
if (kind === "tool" || _optionalChain([brush, 'access', _66 => _66.behaviour, 'optionalAccess', _67 => _67.surface]) !== "wet") {
|
|
2413
2502
|
drop("ghost", "it needs a mark brush with behaviour.surface wet");
|
|
2414
2503
|
delete brush.ghost;
|
|
2415
2504
|
} else {
|
|
@@ -2417,7 +2506,7 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2417
2506
|
drop("light", "ghost paint uses the wet light channel as its tracer");
|
|
2418
2507
|
delete brush.light;
|
|
2419
2508
|
}
|
|
2420
|
-
if (_optionalChain([brush, 'access',
|
|
2509
|
+
if (_optionalChain([brush, 'access', _68 => _68.behaviour, 'optionalAccess', _69 => _69.exchange])) {
|
|
2421
2510
|
drop("behaviour.exchange", "ghost paint does not pick paint up");
|
|
2422
2511
|
delete brush.behaviour.exchange;
|
|
2423
2512
|
}
|
|
@@ -2517,30 +2606,31 @@ function checkBrush(brush, profile) {
|
|
|
2517
2606
|
const image = brush.tip.shape === "stamp" && (_nullishCoalesce(brush.tip.stamps, () => ( []))).some(isBrushSourceRef);
|
|
2518
2607
|
add("tip.shape", "error", `${host} can't lay a ${image ? "stamp tip (image tips are stamps)" : `${brush.tip.shape} tip`}.`, `Set tip.shape to one of: ${list(profile.tipShapes)}.`);
|
|
2519
2608
|
}
|
|
2520
|
-
const marks = _nullishCoalesce(_optionalChain([brush, 'access',
|
|
2609
|
+
const marks = _nullishCoalesce(_optionalChain([brush, 'access', _70 => _70.marks, 'optionalAccess', _71 => _71.kind]), () => ( "continuous"));
|
|
2521
2610
|
if (!profile.marks.includes(marks)) add("marks", "error", `${host} can't lay ${marks} marks.`, `Use marks ${list(profile.marks)} (remove marks for continuous dabs).`);
|
|
2522
|
-
const surface = _nullishCoalesce(_optionalChain([brush, 'access',
|
|
2611
|
+
const surface = _nullishCoalesce(_optionalChain([brush, 'access', _72 => _72.behaviour, 'optionalAccess', _73 => _73.surface]), () => ( "dry"));
|
|
2523
2612
|
if (brush.kind === "mark" && !profile.surfaces.includes(surface)) add("behaviour.surface", "error", `${host} has no ${surface} surface.`, `Set behaviour.surface to ${list(profile.surfaces)}.`);
|
|
2524
|
-
const ex = _optionalChain([brush, 'access',
|
|
2525
|
-
feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess',
|
|
2526
|
-
feature(profile.exchange, !_optionalChain([ex, 'optionalAccess',
|
|
2527
|
-
feature(profile.grain, nonZero(_optionalChain([brush, 'access',
|
|
2528
|
-
feature(profile.light, nonZero(_optionalChain([brush, 'access',
|
|
2613
|
+
const ex = _optionalChain([brush, 'access', _74 => _74.behaviour, 'optionalAccess', _75 => _75.exchange]);
|
|
2614
|
+
feature(profile.reservoir, !!_optionalChain([ex, 'optionalAccess', _76 => _76.reservoir]), "behaviour.exchange.reservoir", "a Mixer Brush reservoir", "Remove behaviour.exchange.reservoir.");
|
|
2615
|
+
feature(profile.exchange, !_optionalChain([ex, 'optionalAccess', _77 => _77.reservoir]) && (nonZero(_optionalChain([ex, 'optionalAccess', _78 => _78.pickup])) || !!_optionalChain([ex, 'optionalAccess', _79 => _79.dirty])), "behaviour.exchange", "picking paint up", "Remove behaviour.exchange.");
|
|
2616
|
+
feature(profile.grain, nonZero(_optionalChain([brush, 'access', _80 => _80.behaviour, 'optionalAccess', _81 => _81.grain])), "behaviour.grain", "paper grain", "Set behaviour.grain to 0.");
|
|
2617
|
+
feature(profile.light, nonZero(_optionalChain([brush, 'access', _82 => _82.light, 'optionalAccess', _83 => _83.amount])), "light", "light paint (glow and spill)", "Remove light (or set light.amount to 0).");
|
|
2529
2618
|
feature(_nullishCoalesce(profile.livePatterns, () => ( "none")), Boolean(brush.livePatterns), "livePatterns", "live reaction-diffusion patterns", "Remove livePatterns.");
|
|
2530
2619
|
const smartInks = profile.id === "paint" ? "full" : "none";
|
|
2531
|
-
feature(smartInks, nonZero(_optionalChain([brush, 'access',
|
|
2532
|
-
feature(smartInks, Boolean(_optionalChain([brush, 'access',
|
|
2620
|
+
feature(smartInks, nonZero(_optionalChain([brush, 'access', _84 => _84.fluorescence, 'optionalAccess', _85 => _85.amount])), "fluorescence", "UV-fluorescent ink", "Remove fluorescence (or set fluorescence.amount to 0).");
|
|
2621
|
+
feature(smartInks, Boolean(_optionalChain([brush, 'access', _86 => _86.thermochromic, 'optionalAccess', _87 => _87.hotColor])), "thermochromic", "thermochromic ink", "Remove thermochromic.");
|
|
2533
2622
|
feature(_nullishCoalesce(profile.iridescence, () => ( "none")), !!brush.iridescence, "iridescence", "thin-film iridescence", "Remove iridescence.");
|
|
2534
2623
|
feature(profile.surfaces.includes("wet") && profile.light === "full" ? "full" : "none", !!brush.ghost, "ghost", "ghost paint", "Remove ghost.");
|
|
2535
2624
|
if (brush.mutation) {
|
|
2536
2625
|
if (profile.id !== "paint") feature("none", true, "mutation", "mutation paint", "Remove mutation.");
|
|
2537
2626
|
else if (brush.kind === "tool") add("mutation", "error", "Tools work on paint already down and cannot be mutation brushes.", "Use a mark brush, or remove mutation.");
|
|
2538
|
-
else if (_optionalChain([brush, 'access',
|
|
2539
|
-
else if (_optionalChain([
|
|
2540
|
-
else if (
|
|
2541
|
-
else if (
|
|
2627
|
+
else if (_optionalChain([brush, 'access', _88 => _88.marks, 'optionalAccess', _89 => _89.kind]) === "objects") add("mutation", "error", "Sticker brushes place objects rather than paint strokes and cannot be mutation brushes.", "Remove marks (or use continuous marks), or remove mutation.");
|
|
2628
|
+
else if (_optionalChain([brush, 'access', _90 => _90.marks, 'optionalAccess', _91 => _91.kind]) === "antimatter") add("mutation", "error", "Antimatter brushes detonate paint already down and cannot be mutation brushes.", "Remove marks (or use continuous marks), or remove mutation.");
|
|
2629
|
+
else if (_optionalChain([ex, 'optionalAccess', _92 => _92.reservoir])) add("mutation", "error", "A Mixer Brush reads paint from the layer beneath and cannot be a mutation brush.", "Remove behaviour.exchange.reservoir, or remove mutation.");
|
|
2630
|
+
else if (nonZero(_optionalChain([ex, 'optionalAccess', _93 => _93.pickup])) || !!_optionalChain([ex, 'optionalAccess', _94 => _94.dirty])) add("mutation", "error", "Mutation brushes must lay their own colour without picking up paint from beneath.", "Remove behaviour.exchange (or set pickup to 0 and dirty to false), or remove mutation.");
|
|
2631
|
+
else if (surface === "wet" && nonZero(_optionalChain([brush, 'access', _95 => _95.light, 'optionalAccess', _96 => _96.amount]))) add("mutation", "error", "Wet mutation brushes use the wet light channel as their fade tracer.", "Remove light (or set light.amount to 0), or remove mutation.");
|
|
2542
2632
|
}
|
|
2543
|
-
feature(_nullishCoalesce(profile.ferro, () => ( "none")), nonZero(_optionalChain([brush, 'access',
|
|
2633
|
+
feature(_nullishCoalesce(profile.ferro, () => ( "none")), nonZero(_optionalChain([brush, 'access', _97 => _97.ferro, 'optionalAccess', _98 => _98.amount])), "ferro", "ferrofluid spikes and magnets", "Remove ferro (or set ferro.amount to 0).");
|
|
2544
2634
|
const m = brush.motion;
|
|
2545
2635
|
feature(profile.motion, !!m && (!!m.live || nonZero(m.waveSpeed) || m.fps !== void 0), "motion", "animation", "Remove motion.");
|
|
2546
2636
|
const d = _nullishCoalesce(brush.dynamics, () => ( {}));
|
|
@@ -2549,16 +2639,16 @@ function checkBrush(brush, profile) {
|
|
|
2549
2639
|
feature(profile.velocity, nonZero(d.velocitySize) || nonZero(d.velocityOpacity), "dynamics.velocity", "velocity dynamics (its strokes carry no timing)", "Set dynamics.velocitySize and velocityOpacity to 0.");
|
|
2550
2640
|
feature(profile.tilt, nonZero(d.tiltSize) || nonZero(d.tiltRoundness) || nonZero(d.tiltOpacity), "dynamics.tilt", "tilt dynamics", "Set dynamics.tiltSize, tiltRoundness and tiltOpacity to 0.");
|
|
2551
2641
|
const colour = brush.colour;
|
|
2552
|
-
if (_optionalChain([colour, 'optionalAccess',
|
|
2642
|
+
if (_optionalChain([colour, 'optionalAccess', _99 => _99.default]) !== void 0) {
|
|
2553
2643
|
const kind = brushColourKind(colour.default);
|
|
2554
2644
|
if (!profile.colours.includes(kind)) add("colour.default", "error", `${host} can't paint ${kind} colours.`, `Use a ${list(profile.colours)} colour, or remove colour.default.`);
|
|
2555
2645
|
}
|
|
2556
|
-
const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess',
|
|
2646
|
+
const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _100 => _100.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
|
|
2557
2647
|
if (foreign.length) add("colour.palette", "warning", `${host} skips the palette's ${list(foreign)} colours.`, `Nothing to do; or keep to ${list(profile.colours)} colours.`);
|
|
2558
2648
|
return { ok: !issues.some((i) => i.severity === "error"), issues };
|
|
2559
2649
|
}
|
|
2560
2650
|
function withKeptIssues(check, before) {
|
|
2561
|
-
const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess',
|
|
2651
|
+
const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess', _101 => _101.issues]), () => ( []))).filter((i) => i.severity === "error").map((i) => i.facet));
|
|
2562
2652
|
const kept = check.issues.filter((i) => i.severity === "error" && had.has(i.facet));
|
|
2563
2653
|
const issues = check.issues.filter((i) => !kept.includes(i));
|
|
2564
2654
|
return { ok: !issues.some((i) => i.severity === "error"), issues, kept };
|
|
@@ -2657,7 +2747,7 @@ function degrade(brush, profile, options = {}) {
|
|
|
2657
2747
|
}
|
|
2658
2748
|
dropped.push(issue);
|
|
2659
2749
|
}
|
|
2660
|
-
if (_optionalChain([b, 'access',
|
|
2750
|
+
if (_optionalChain([b, 'access', _102 => _102.behaviour, 'optionalAccess', _103 => _103.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
|
|
2661
2751
|
if (b.colour && !Object.keys(b.colour).length) delete b.colour;
|
|
2662
2752
|
const after = checkBrush(b, profile).issues.filter((i) => i.severity === "error");
|
|
2663
2753
|
return { brush: b, dropped, issues: after };
|
|
@@ -2701,7 +2791,7 @@ function parseBrushLibrary2(raw, problems = []) {
|
|
|
2701
2791
|
if (file && file.version !== void 0 && file.version !== 1 && file.version !== 2) {
|
|
2702
2792
|
throw new BrushLibraryError("invalid", `Brush library version ${JSON.stringify(file.version)} is not supported; this library reads versions 1 and 2.`);
|
|
2703
2793
|
}
|
|
2704
|
-
const v1File = _optionalChain([file, 'optionalAccess',
|
|
2794
|
+
const v1File = _optionalChain([file, 'optionalAccess', _104 => _104.version]) === 1;
|
|
2705
2795
|
const out = [];
|
|
2706
2796
|
items.forEach((item, i) => {
|
|
2707
2797
|
const at = `brushes[${i}]`;
|
|
@@ -2962,7 +3052,7 @@ function snapshotBrushLibrary(library, onChange) {
|
|
|
2962
3052
|
(list2) => {
|
|
2963
3053
|
entries = list2;
|
|
2964
3054
|
user = list2.filter((e) => !e.builtin).map((e) => e.brush);
|
|
2965
|
-
_optionalChain([onChange, 'optionalCall',
|
|
3055
|
+
_optionalChain([onChange, 'optionalCall', _105 => _105()]);
|
|
2966
3056
|
},
|
|
2967
3057
|
() => void 0
|
|
2968
3058
|
);
|
|
@@ -3106,4 +3196,7 @@ function snapshotBrushLibrary(library, onChange) {
|
|
|
3106
3196
|
|
|
3107
3197
|
|
|
3108
3198
|
|
|
3109
|
-
|
|
3199
|
+
|
|
3200
|
+
|
|
3201
|
+
|
|
3202
|
+
exports.BRUSH_PRESETS = BRUSH_PRESETS; exports.MAX_STICKER_STAMPS = MAX_STICKER_STAMPS; exports.DEFAULT_STICKER = DEFAULT_STICKER; exports.normalizeStickerSettings = normalizeStickerSettings; exports.PARTICLE_KINDS = PARTICLE_KINDS; exports.PARTICLE_RENDERS = PARTICLE_RENDERS; exports.RIBBON_PAIRS = RIBBON_PAIRS; exports.DOT_TEXTURE_ORDERS = DOT_TEXTURE_ORDERS; exports.DOT_ROTATIONS = DOT_ROTATIONS; exports.MAX_DOT_TEXTURES = MAX_DOT_TEXTURES; exports.DEFAULT_PARTICLE = DEFAULT_PARTICLE; exports.normalizeParticle = normalizeParticle; exports.DEFAULT_BRISTLE = DEFAULT_BRISTLE; exports.normalizeBristle = normalizeBristle; exports.INVERT_MODES = INVERT_MODES; exports.DEFAULT_ANTIMATTER = DEFAULT_ANTIMATTER; exports.normalizeAntimatter = normalizeAntimatter; exports.PAINT_BRUSH_ENGINES = PAINT_BRUSH_ENGINES; exports.PAINT_BRUSH_CATEGORIES = PAINT_BRUSH_CATEGORIES; exports.WET_TOOLS = WET_TOOLS; exports.WET_MEDIA = WET_MEDIA; exports.DEFAULT_WET_BRUSH = DEFAULT_WET_BRUSH; exports.normalizeWetBrush = normalizeWetBrush; exports.IMPASTO_TOOLS = IMPASTO_TOOLS; exports.DEFAULT_IMPASTO = DEFAULT_IMPASTO; exports.DEFAULT_LIGHT = DEFAULT_LIGHT; exports.normalizeLight = normalizeLight; exports.DEFAULT_FLUORESCENCE = DEFAULT_FLUORESCENCE; exports.normalizeFluorescence = normalizeFluorescence; exports.DEFAULT_THERMOCHROMIC = DEFAULT_THERMOCHROMIC; exports.normalizeThermochromic = normalizeThermochromic; exports.DEFAULT_IRIDESCENCE = DEFAULT_IRIDESCENCE; exports.GHOST_TRIGGERS = GHOST_TRIGGERS; exports.DEFAULT_GHOST = DEFAULT_GHOST; exports.normalizeGhost = normalizeGhost; exports.DEFAULT_MUTATION = DEFAULT_MUTATION; exports.normalizeMutation = normalizeMutation; exports.DEFAULT_FERRO = DEFAULT_FERRO; exports.normalizeFerro = normalizeFerro; exports.normalizeImpasto = normalizeImpasto; exports.MULTI_COLOR_MODES = MULTI_COLOR_MODES; exports.DEFAULT_MULTI_COLOR = DEFAULT_MULTI_COLOR; exports.DEFAULT_BEHAVIOR = DEFAULT_BEHAVIOR; exports.BRUSH_ROTATIONS = BRUSH_ROTATIONS; exports.DAB_FLIPS = DAB_FLIPS; exports.TIP_GRAIN_MODES = TIP_GRAIN_MODES; exports.DEFAULT_TIP_GRAIN = DEFAULT_TIP_GRAIN; exports.DEFAULT_DYNAMICS = DEFAULT_DYNAMICS; exports.normalizeDynamics = normalizeDynamics; exports.BRUSH_ID = BRUSH_ID; exports.normalizeMultiColor = normalizeMultiColor; exports.normalizeBehavior = normalizeBehavior; exports.DEFAULT_SPRAY = DEFAULT_SPRAY; exports.isWetCapable = isWetCapable; exports.isWetBrush = isWetBrush; exports.usesPaintExchange = usesPaintExchange; exports.brushTakesPaint = brushTakesPaint; exports.paintToMultiColor = paintToMultiColor; exports.multiColorToPaint = multiColorToPaint; exports.normalizePaintBrush = normalizePaintBrush; exports.BRUSH_FIELDS = BRUSH_FIELDS; exports.getPath = getPath; exports.setPath = setPath; exports.resolveEngine = resolveEngine; exports.resolveWetMedium = resolveWetMedium; exports.resolveCategory = resolveCategory; exports.resolveBrush = resolveBrush; exports.BUILTIN_BRUSHES = BUILTIN_BRUSHES; exports.DEFAULT_BRUSH_ID = DEFAULT_BRUSH_ID; exports.brushToJSON = brushToJSON; exports.parseBrushLibrary = parseBrushLibrary; exports.migrateBrushV1 = migrateBrushV1; exports.BRUSH_KINDS = BRUSH_KINDS; exports.BRUSH_MEDIA = BRUSH_MEDIA; exports.BRUSH_TOOLS = BRUSH_TOOLS; exports.BRUSH_TIP_SHAPES = BRUSH_TIP_SHAPES; exports.BRUSH_MARKS_KINDS = BRUSH_MARKS_KINDS; exports.BRUSH_SURFACES = BRUSH_SURFACES; exports.BRUSH_GRAIN_MODES = BRUSH_GRAIN_MODES; exports.BRUSH_FLIPS = BRUSH_FLIPS; exports.GHOST_TRIGGERS2 = GHOST_TRIGGERS2; exports.MAX_BRUSH_PALETTE = MAX_BRUSH_PALETTE; exports.BRUSH_WORD = BRUSH_WORD; exports.TIP_GRAIN_PATTERNS = TIP_GRAIN_PATTERNS; exports.BRUSH_GRAIN_SOURCE_PATTERN = BRUSH_GRAIN_SOURCE_PATTERN; exports.BRUSH_JSON_SCHEMA = BRUSH_JSON_SCHEMA; exports.BRUSH_FACET_SCHEMAS = BRUSH_FACET_SCHEMAS; exports.BRUSH_SOURCE_PROVIDER = BRUSH_SOURCE_PROVIDER; exports.MAX_BRUSH_SOURCE_SIZE = MAX_BRUSH_SOURCE_SIZE; exports.MAX_BRUSH_SOURCE_INPUT_PIXELS = MAX_BRUSH_SOURCE_INPUT_PIXELS; exports.MAX_BRUSH_SOURCES = MAX_BRUSH_SOURCES; exports.BRUSH_SOURCE_CHANNELS = BRUSH_SOURCE_CHANNELS; exports.BrushSourceError = BrushSourceError; exports.brushSourceRef = brushSourceRef; exports.isBrushSourceRef = isBrushSourceRef; exports.brushSourceIdOf = brushSourceIdOf; exports.brushSourceIds = brushSourceIds; exports.summarizeBrushSource = summarizeBrushSource; exports.brushSourceIdFromName = brushSourceIdFromName; exports.brushSourceFromMask = brushSourceFromMask; exports.makeBrushSource = makeBrushSource; exports.readBrushSource = readBrushSource; exports.decodeBrushSource = decodeBrushSource; exports.WET_BRUSH_TOOLS = WET_BRUSH_TOOLS; exports.normalizeBrushSpec = normalizeBrushSpec; exports.PAINT_PROFILE = PAINT_PROFILE; exports.IMAGE_PROFILE = IMAGE_PROFILE; exports.CANVAS_PROFILE = CANVAS_PROFILE; exports.VECTOR_PROFILE = VECTOR_PROFILE; exports.BRUSH_HOST_PROFILES = BRUSH_HOST_PROFILES; exports.brushColourKind = brushColourKind; exports.checkBrush = checkBrush; exports.withKeptIssues = withKeptIssues; exports.checkBrushEdit = checkBrushEdit; exports.listPresets = listPresets; exports.degrade = degrade; exports.BrushLibraryError = BrushLibraryError; exports.isBrushLibrary = isBrushLibrary; exports.parseBrushLibrarySources = parseBrushLibrarySources; exports.parseBrushLibrary2 = parseBrushLibrary2; exports.createBrushLibrary = createBrushLibrary; exports.closest = closest; exports.snapshotBrushLibrary = snapshotBrushLibrary;
|