@pixerate/editor 0.280.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/edge-animation-tools.d.cts +115 -0
- package/dist/canvas/edge-animation-tools.d.ts +115 -0
- package/dist/canvas/edgeAnimation.d.cts +164 -0
- package/dist/canvas/edgeAnimation.d.ts +164 -0
- package/dist/canvas/edgePaths.d.cts +63 -0
- package/dist/canvas/edgePaths.d.ts +63 -0
- package/dist/canvas/index.cjs +691 -21
- package/dist/canvas/index.d.cts +3 -0
- package/dist/canvas/index.d.ts +3 -0
- package/dist/canvas/index.js +679 -9
- 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-canvas/SKILL.md +25 -2
- 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 = 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 = 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 = 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: normalizeBrush({ ...b.tip, ...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(raw.dynamics ?? {}, b.dynamics),
|
|
1351
1416
|
mixer,
|
|
@@ -1358,6 +1423,7 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1358
1423
|
particle: normalizeParticle(raw.particle ?? {}, b.particle ?? DEFAULT_PARTICLE),
|
|
1359
1424
|
bristle: normalizeBristle(raw.bristle ?? {}, b.bristle ?? DEFAULT_BRISTLE),
|
|
1360
1425
|
sticker: normalizeStickerSettings(raw.sticker ?? {}, b.sticker ?? DEFAULT_STICKER),
|
|
1426
|
+
antimatter: normalizeAntimatter(raw.antimatter ?? {}, b.antimatter ?? DEFAULT_ANTIMATTER),
|
|
1361
1427
|
light: ghost && !wantsLight ? { ...DEFAULT_LIGHT } : normalizeLight(raw.light ?? {}, b.light ?? DEFAULT_LIGHT),
|
|
1362
1428
|
fluorescence: normalizeFluorescence(raw.fluorescence ?? {}, b.fluorescence ?? DEFAULT_FLUORESCENCE),
|
|
1363
1429
|
thermochromic: normalizeThermochromic(raw.thermochromic ?? {}, 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,6 +1588,7 @@ 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";
|
|
1591
|
+
if (brush.marks?.kind === "antimatter") return "antimatter";
|
|
1523
1592
|
if (brush.marks?.kind === "particles") return "particle";
|
|
1524
1593
|
if (brush.marks?.kind === "objects") return "sticker";
|
|
1525
1594
|
if (brush.tip.shape === "bristle") return "bristle";
|
|
@@ -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: {
|
|
@@ -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,
|
|
@@ -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,8 +2413,8 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2324
2413
|
delete brush.iridescence;
|
|
2325
2414
|
}
|
|
2326
2415
|
}
|
|
2327
|
-
if (brush.iridescence && brush.marks?.kind === "objects") {
|
|
2328
|
-
drop("iridescence", "object marks are stickers, not film");
|
|
2416
|
+
if (brush.iridescence && (brush.marks?.kind === "objects" || brush.marks?.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
2420
|
if (brush.marks?.kind === "scatter") {
|
|
@@ -2363,7 +2452,7 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2363
2452
|
if (brush.tip.grain) {
|
|
2364
2453
|
const surface = brush.behaviour?.surface;
|
|
2365
2454
|
const marks = brush.marks?.kind;
|
|
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;
|
|
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,12 +2488,12 @@ 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 && (brush.marks?.kind === "particles" || brush.marks?.kind === "objects" || brush.tip.shape === "bristle")) {
|
|
2403
|
-
drop("behaviour.exchange", "particle, object and bristle marks do not pick paint up");
|
|
2491
|
+
} else if (b.exchange && (brush.marks?.kind === "particles" || brush.marks?.kind === "objects" || brush.marks?.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" || brush.behaviour?.surface !== "wet" || brush.marks?.kind === "particles" || brush.marks?.kind === "objects" || brush.tip.shape === "bristle")) {
|
|
2496
|
+
if (brush.livePatterns && (kind !== "mark" || brush.behaviour?.surface !== "wet" || brush.marks?.kind === "particles" || brush.marks?.kind === "objects" || brush.marks?.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
|
}
|
|
@@ -2536,6 +2625,7 @@ function checkBrush(brush, profile) {
|
|
|
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
2627
|
else if (brush.marks?.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 (brush.marks?.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.");
|
|
2539
2629
|
else if (ex?.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.");
|
|
2540
2630
|
else if (nonZero(ex?.pickup) || !!ex?.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.");
|
|
2541
2631
|
else if (surface === "wet" && nonZero(brush.light?.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.");
|
|
@@ -3000,6 +3090,9 @@ export {
|
|
|
3000
3090
|
normalizeParticle,
|
|
3001
3091
|
DEFAULT_BRISTLE,
|
|
3002
3092
|
normalizeBristle,
|
|
3093
|
+
INVERT_MODES,
|
|
3094
|
+
DEFAULT_ANTIMATTER,
|
|
3095
|
+
normalizeAntimatter,
|
|
3003
3096
|
PAINT_BRUSH_ENGINES,
|
|
3004
3097
|
PAINT_BRUSH_CATEGORIES,
|
|
3005
3098
|
WET_TOOLS,
|