@pixerate/editor 0.276.0 → 0.278.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 +69 -67
- package/dist/brushes/index.js +6 -4
- package/dist/brushes/patch.d.cts +4 -4
- package/dist/brushes/patch.d.ts +4 -4
- package/dist/brushes/profiles.d.cts +2 -0
- package/dist/brushes/profiles.d.ts +2 -0
- package/dist/brushes/schema.d.cts +1 -0
- package/dist/brushes/schema.d.ts +1 -0
- package/dist/brushes/types.d.cts +10 -0
- package/dist/brushes/types.d.ts +10 -0
- package/dist/{brushstrokeRender-I6MYFCOU.cjs → brushstrokeRender-7HOMKZNO.cjs} +15 -15
- package/dist/{brushstrokeRender-FK3ASUUJ.js → brushstrokeRender-EIK3625T.js} +3 -3
- package/dist/canvas/index.cjs +13 -13
- package/dist/canvas/index.js +1 -1
- package/dist/{chunk-U26LUXCJ.cjs → chunk-4NZTK7LM.cjs} +35 -35
- package/dist/{chunk-CVBTJVRN.js → chunk-DWPFGWW5.js} +1 -1
- package/dist/{chunk-XMSH66VU.js → chunk-FNIWHSLI.js} +1 -1
- package/dist/{chunk-QNNZA3V5.cjs → chunk-H3EME3S5.cjs} +2 -2
- package/dist/{chunk-4EM5NGCL.js → chunk-HHX7ST6Z.js} +1 -1
- package/dist/{chunk-Q33V5PEF.cjs → chunk-HRUK5TFW.cjs} +73 -12
- package/dist/{chunk-5HR5CSLC.cjs → chunk-JVFGK3DK.cjs} +69 -58
- package/dist/{chunk-JNMNM3SL.js → chunk-LZE2QZCT.js} +1 -1
- package/dist/{chunk-OS6OG7DN.js → chunk-N4MCWQZ7.js} +1 -1
- package/dist/{chunk-IJ6NSWKM.js → chunk-NJLPW4MM.js} +17 -6
- package/dist/{chunk-OY24XRYF.cjs → chunk-PEQWARCP.cjs} +12 -12
- package/dist/{chunk-XVPQNX7O.js → chunk-PPDUCZZV.js} +66 -5
- package/dist/{chunk-X7XBEX3O.cjs → chunk-QBZEC2JJ.cjs} +86 -86
- package/dist/{chunk-GHYJAMMS.js → chunk-ROURHJYT.js} +1 -1
- package/dist/{chunk-ZIE6EJGR.cjs → chunk-VNF7A2JA.cjs} +23 -23
- package/dist/{chunk-ISCAJBPQ.cjs → chunk-WFSYZO5Z.cjs} +1 -1
- package/dist/image-editor/index.cjs +788 -788
- package/dist/image-editor/index.js +4 -4
- package/dist/paint-editor/brush-model.d.cts +15 -1
- package/dist/paint-editor/brush-model.d.ts +15 -1
- package/dist/paint-editor/controller.d.cts +90 -9
- package/dist/paint-editor/controller.d.ts +90 -9
- package/dist/paint-editor/document.d.cts +8 -1
- package/dist/paint-editor/document.d.ts +8 -1
- package/dist/paint-editor/ferro-tools.d.cts +10 -0
- package/dist/paint-editor/ferro-tools.d.ts +10 -0
- package/dist/paint-editor/ferro.d.cts +134 -0
- package/dist/paint-editor/ferro.d.ts +134 -0
- package/dist/paint-editor/index.cjs +2138 -872
- package/dist/paint-editor/index.d.cts +2 -0
- package/dist/paint-editor/index.d.ts +2 -0
- package/dist/paint-editor/index.js +1446 -180
- package/dist/paint-editor/serialize.d.cts +3 -1
- package/dist/paint-editor/serialize.d.ts +3 -1
- package/dist/paint-editor/stroke.d.cts +17 -0
- package/dist/paint-editor/stroke.d.ts +17 -0
- package/dist/paint-editor/strokes.d.cts +11 -1
- package/dist/paint-editor/strokes.d.ts +11 -1
- package/dist/paint-editor/thick.d.cts +15 -2
- package/dist/paint-editor/thick.d.ts +15 -2
- package/dist/paint-editor/ui.d.cts +2 -0
- package/dist/paint-editor/ui.d.ts +2 -0
- package/dist/vector/index.cjs +998 -998
- package/dist/vector/index.js +4 -4
- package/package.json +1 -1
- package/skills/pixerate-brushes/SKILL.md +1 -0
- package/skills/pixerate-paint-editor/SKILL.md +12 -30
- package/skills/pixerate-paint-editor/references/brush-facets.md +1 -0
- package/skills/pixerate-paint-editor/references/ferrofluid.md +36 -0
|
@@ -932,6 +932,29 @@ var BRUSH_PRESETS = [
|
|
|
932
932
|
tip: { shape: "round", size: 6, hardness: 0.9, spacing: 0.06 },
|
|
933
933
|
dynamics: { smoothing: 0.35, pressureSmoothing: 0.25, minSize: 0.25 },
|
|
934
934
|
mutation: {}
|
|
935
|
+
},
|
|
936
|
+
// --- Ferrofluid paint: liquid magnetic paint that rises into lit Rosensweig spikes near magnets ---
|
|
937
|
+
{
|
|
938
|
+
id: "ferrofluid",
|
|
939
|
+
name: "Ferrofluid",
|
|
940
|
+
kind: "mark",
|
|
941
|
+
medium: "paint",
|
|
942
|
+
variety: "ferrofluid",
|
|
943
|
+
tip: { shape: "round", size: 28, hardness: 0.75, flow: 0.9 },
|
|
944
|
+
dynamics: { smoothing: 0.35 },
|
|
945
|
+
ferro: { amount: 0.85 },
|
|
946
|
+
colour: { default: "#111827", palette: ["#111827", "#1e293b", "#312e81", "#0f3d3e", "#3b0764", "#451a03"] }
|
|
947
|
+
},
|
|
948
|
+
{
|
|
949
|
+
id: "ferro-ink",
|
|
950
|
+
name: "Ferro ink",
|
|
951
|
+
kind: "mark",
|
|
952
|
+
medium: "ink",
|
|
953
|
+
variety: "ferrofluid",
|
|
954
|
+
tip: { shape: "round", size: 12, spacing: 0.08 },
|
|
955
|
+
dynamics: { smoothing: 0.45, minSize: 0.25, velocitySize: -0.25 },
|
|
956
|
+
ferro: { amount: 0.7, wavelength: 12, threshold: 0.15 },
|
|
957
|
+
colour: { default: "#0f172a" }
|
|
935
958
|
}
|
|
936
959
|
];
|
|
937
960
|
|
|
@@ -1101,6 +1124,18 @@ function normalizeMutation(raw = {}, base = DEFAULT_MUTATION) {
|
|
|
1101
1124
|
fade: range(raw.fade, 0.5, 10, base.fade)
|
|
1102
1125
|
};
|
|
1103
1126
|
}
|
|
1127
|
+
var DEFAULT_FERRO = { amount: 0, wavelength: 16, threshold: 0.12 };
|
|
1128
|
+
function normalizeFerro(raw = {}, base = DEFAULT_FERRO) {
|
|
1129
|
+
if (typeof raw === "number") {
|
|
1130
|
+
return { amount: unit2(raw, base.amount), wavelength: base.wavelength, threshold: base.threshold };
|
|
1131
|
+
}
|
|
1132
|
+
const r = _nullishCoalesce(raw, () => ( {}));
|
|
1133
|
+
return {
|
|
1134
|
+
amount: unit2(r.amount, base.amount),
|
|
1135
|
+
wavelength: range(r.wavelength, 4, 64, base.wavelength),
|
|
1136
|
+
threshold: range(r.threshold, 0.01, 0.95, base.threshold)
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1104
1139
|
function normalizeImpasto(raw = {}, base = DEFAULT_IMPASTO) {
|
|
1105
1140
|
return {
|
|
1106
1141
|
tool: IMPASTO_TOOLS.includes(raw.tool) ? raw.tool : base.tool,
|
|
@@ -1329,6 +1364,7 @@ function normalizePaintBrush(raw = {}, base) {
|
|
|
1329
1364
|
...withIridescence(readIridescence(raw.iridescence, _nullishCoalesce(b.iridescence, () => ( null)))),
|
|
1330
1365
|
...ghost ? { ghost } : {},
|
|
1331
1366
|
...mutation ? { mutation } : {},
|
|
1367
|
+
ferro: normalizeFerro(raw.ferro, _nullishCoalesce(b.ferro, () => ( DEFAULT_FERRO))),
|
|
1332
1368
|
stamp: readStamp(raw.stamp, _nullishCoalesce(b.stamp, () => ( null))),
|
|
1333
1369
|
spray: readSpray(raw.spray, _nullishCoalesce(b.spray, () => ( null))),
|
|
1334
1370
|
...withTipGrain(readTipGrain(raw.tipGrain, _nullishCoalesce(b.tipGrain, () => ( null)))),
|
|
@@ -1360,6 +1396,7 @@ var BASE_BRUSH = {
|
|
|
1360
1396
|
light: { ...DEFAULT_LIGHT },
|
|
1361
1397
|
fluorescence: { ...DEFAULT_FLUORESCENCE },
|
|
1362
1398
|
thermochromic: { ...DEFAULT_THERMOCHROMIC },
|
|
1399
|
+
ferro: { ...DEFAULT_FERRO },
|
|
1363
1400
|
stamp: null,
|
|
1364
1401
|
spray: null,
|
|
1365
1402
|
paint: null
|
|
@@ -1419,6 +1456,7 @@ var BRUSH_FIELDS = [
|
|
|
1419
1456
|
...each("fluorescence", "fluorescence", ["amount", "invisible"]),
|
|
1420
1457
|
...each("thermochromic", "thermochromic", ["hotColor", "threshold"]),
|
|
1421
1458
|
...each("iridescence", "iridescence", ["thickness", "pressureToThickness", "ior"], FILM),
|
|
1459
|
+
...each("ferro", "ferro", ["amount", "wavelength", "threshold"]),
|
|
1422
1460
|
// Paint exchange: the dab, wet and impasto engines' behaviour, or the Mixer Brush's settings.
|
|
1423
1461
|
f("behaviour.exchange.pickup", "behavior.pickup", EXCHANGE),
|
|
1424
1462
|
f("behaviour.exchange.mix", "behavior.mix", EXCHANGE),
|
|
@@ -1627,7 +1665,7 @@ function skeleton(b) {
|
|
|
1627
1665
|
}
|
|
1628
1666
|
}
|
|
1629
1667
|
}
|
|
1630
|
-
var ORDER = ["id", "name", "description", "tags", "kind", "medium", "variety", "tool", "tip", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "motion", "livePatterns", "colour"];
|
|
1668
|
+
var ORDER = ["id", "name", "description", "tags", "kind", "medium", "variety", "tool", "tip", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "ferro", "motion", "livePatterns", "colour"];
|
|
1631
1669
|
function migrateBrushV1(raw) {
|
|
1632
1670
|
const b = normalizePaintBrush(raw);
|
|
1633
1671
|
const brush = skeleton(b);
|
|
@@ -1866,6 +1904,11 @@ var MUTATION = object("Mutation paint: you paint something and pause; once an ag
|
|
|
1866
1904
|
patience: num(5, 300, "Seconds to wait for an agent before giving up and keeping the paint as ordinary paint (default 45)."),
|
|
1867
1905
|
fade: num(0.5, 10, "Seconds the paint takes to sink away once claimed by read_mutation (default 2).")
|
|
1868
1906
|
});
|
|
1907
|
+
var FERRO = object("Liquid ferrofluid paint: rises into glossy Rosensweig spikes near magnets until cured.", {
|
|
1908
|
+
amount: unit3("How much liquid ferrofluid the brush lays per dab (default 0: none)."),
|
|
1909
|
+
wavelength: num(4, 64, "Capillary wavelength (spike-to-spike spacing) in pixels (default 16)."),
|
|
1910
|
+
threshold: num(0.01, 0.95, "Critical magnetic field |B| threshold where spikes begin to rise (default 0.12).")
|
|
1911
|
+
});
|
|
1869
1912
|
var MOTION = object("Animation after painting.", {
|
|
1870
1913
|
live: bool("Effect paint keeps playing on stroke layers (default false)."),
|
|
1871
1914
|
fps: int(1, 60, "Suggested playback rate in frames per second."),
|
|
@@ -1947,6 +1990,7 @@ var BRUSH_JSON_SCHEMA = object(
|
|
|
1947
1990
|
iridescence: IRIDESCENCE,
|
|
1948
1991
|
ghost: GHOST,
|
|
1949
1992
|
mutation: MUTATION,
|
|
1993
|
+
ferro: FERRO,
|
|
1950
1994
|
motion: MOTION,
|
|
1951
1995
|
livePatterns: LIVE_PATTERNS,
|
|
1952
1996
|
colour: COLOUR
|
|
@@ -1965,6 +2009,7 @@ var BRUSH_FACET_SCHEMAS = {
|
|
|
1965
2009
|
iridescence: IRIDESCENCE,
|
|
1966
2010
|
ghost: GHOST,
|
|
1967
2011
|
mutation: MUTATION,
|
|
2012
|
+
ferro: FERRO,
|
|
1968
2013
|
motion: MOTION,
|
|
1969
2014
|
livePatterns: LIVE_PATTERNS,
|
|
1970
2015
|
colour: COLOUR,
|
|
@@ -2210,14 +2255,14 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2210
2255
|
else if (raw.kind === void 0) kind = tool ? "tool" : "mark";
|
|
2211
2256
|
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).`);
|
|
2212
2257
|
if (kind === "tool" && !tool) throw new Error(`Brush "${raw.id}" is a tool and needs tool: one of ${BRUSH_TOOLS.join(", ")}.`);
|
|
2213
|
-
const { colour: rawColour, marks: rawMarks, kind: _k, id: _i, name: _n, tool: _t, ...rest } = raw;
|
|
2258
|
+
const { colour: rawColour, marks: rawMarks, ferro: rawFerro, kind: _k, id: _i, name: _n, tool: _t, ...rest } = raw;
|
|
2214
2259
|
if (typeof rest.fluorescence === "number" && Number.isFinite(rest.fluorescence)) rest.fluorescence = { amount: rest.fluorescence };
|
|
2215
2260
|
const out = readObject(rest, BRUSH_JSON_SCHEMA, "brush", problems);
|
|
2216
2261
|
if (_optionalChain([out, 'access', _29 => _29.thermochromic, 'optionalAccess', _30 => _30.hotColor])) out.thermochromic.hotColor = out.thermochromic.hotColor.toLowerCase();
|
|
2217
2262
|
const brush = { id: raw.id, name, ...out, kind, ...tool ? { tool } : {}, tip: _nullishCoalesce(out.tip, () => ( { shape: "round" })) };
|
|
2218
2263
|
const ordered = () => {
|
|
2219
|
-
const { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, fluorescence, thermochromic, iridescence, ghost, mutation, motion, livePatterns, colour } = brush;
|
|
2220
|
-
const all = { id, name: n, description, tags, kind: k, medium, variety, tool: t, tip, marks, dynamics, behaviour, light, fluorescence, thermochromic, iridescence, ghost, mutation, motion, livePatterns, colour };
|
|
2264
|
+
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;
|
|
2265
|
+
const all = { 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 };
|
|
2221
2266
|
return Object.fromEntries(Object.entries(all).filter(([, v]) => v !== void 0));
|
|
2222
2267
|
};
|
|
2223
2268
|
if (!out.tip) problems.push("tip is missing; a round tip is used.");
|
|
@@ -2231,6 +2276,11 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2231
2276
|
if (!schema) problems.push(`marks.kind ${JSON.stringify(k)} is not valid; use continuous, scatter, particles or objects. marks dropped.`);
|
|
2232
2277
|
else brush.marks = readObject(rawMarks, schema, "brush.marks", problems);
|
|
2233
2278
|
}
|
|
2279
|
+
if (rawFerro !== void 0) {
|
|
2280
|
+
const ferroObj = typeof rawFerro === "number" ? { amount: rawFerro } : rawFerro;
|
|
2281
|
+
const f2 = readObject(ferroObj, BRUSH_FACET_SCHEMAS.ferro, "brush.ferro", problems);
|
|
2282
|
+
if (f2 && Object.keys(f2).length) brush.ferro = f2;
|
|
2283
|
+
}
|
|
2234
2284
|
if (rawColour !== void 0) {
|
|
2235
2285
|
const c = readObject(rawColour, { ...BRUSH_FACET_SCHEMAS.colour, properties: { own: BRUSH_FACET_SCHEMAS.colour.properties.own, default: {}, palette: {} } }, "brush.colour", problems);
|
|
2236
2286
|
if (c) {
|
|
@@ -2265,6 +2315,10 @@ function normalizeBrushSpec(raw, problems = []) {
|
|
|
2265
2315
|
drop("marks", "tools lay no marks");
|
|
2266
2316
|
delete brush.marks;
|
|
2267
2317
|
}
|
|
2318
|
+
if (brush.ferro) {
|
|
2319
|
+
drop("ferro", "tools lay no ferrofluid");
|
|
2320
|
+
delete brush.ferro;
|
|
2321
|
+
}
|
|
2268
2322
|
if (brush.iridescence) {
|
|
2269
2323
|
drop("iridescence", "tools lay no film");
|
|
2270
2324
|
delete brush.iridescence;
|
|
@@ -2394,7 +2448,8 @@ var PAINT_PROFILE = {
|
|
|
2394
2448
|
tipGrain: "full",
|
|
2395
2449
|
dabCount: "full",
|
|
2396
2450
|
livePatterns: "full",
|
|
2397
|
-
iridescence: "full"
|
|
2451
|
+
iridescence: "full",
|
|
2452
|
+
ferro: "full"
|
|
2398
2453
|
};
|
|
2399
2454
|
var IMAGE_PROFILE = {
|
|
2400
2455
|
id: "image",
|
|
@@ -2485,6 +2540,7 @@ function checkBrush(brush, profile) {
|
|
|
2485
2540
|
else if (nonZero(_optionalChain([ex, 'optionalAccess', _83 => _83.pickup])) || !!_optionalChain([ex, 'optionalAccess', _84 => _84.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.");
|
|
2486
2541
|
else if (surface === "wet" && nonZero(_optionalChain([brush, 'access', _85 => _85.light, 'optionalAccess', _86 => _86.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.");
|
|
2487
2542
|
}
|
|
2543
|
+
feature(_nullishCoalesce(profile.ferro, () => ( "none")), nonZero(_optionalChain([brush, 'access', _87 => _87.ferro, 'optionalAccess', _88 => _88.amount])), "ferro", "ferrofluid spikes and magnets", "Remove ferro (or set ferro.amount to 0).");
|
|
2488
2544
|
const m = brush.motion;
|
|
2489
2545
|
feature(profile.motion, !!m && (!!m.live || nonZero(m.waveSpeed) || m.fps !== void 0), "motion", "animation", "Remove motion.");
|
|
2490
2546
|
const d = _nullishCoalesce(brush.dynamics, () => ( {}));
|
|
@@ -2493,16 +2549,16 @@ function checkBrush(brush, profile) {
|
|
|
2493
2549
|
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.");
|
|
2494
2550
|
feature(profile.tilt, nonZero(d.tiltSize) || nonZero(d.tiltRoundness) || nonZero(d.tiltOpacity), "dynamics.tilt", "tilt dynamics", "Set dynamics.tiltSize, tiltRoundness and tiltOpacity to 0.");
|
|
2495
2551
|
const colour = brush.colour;
|
|
2496
|
-
if (_optionalChain([colour, 'optionalAccess',
|
|
2552
|
+
if (_optionalChain([colour, 'optionalAccess', _89 => _89.default]) !== void 0) {
|
|
2497
2553
|
const kind = brushColourKind(colour.default);
|
|
2498
2554
|
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.`);
|
|
2499
2555
|
}
|
|
2500
|
-
const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess',
|
|
2556
|
+
const foreign = [...new Set((_nullishCoalesce(_optionalChain([colour, 'optionalAccess', _90 => _90.palette]), () => ( []))).map(brushColourKind).filter((k) => !profile.colours.includes(k)))];
|
|
2501
2557
|
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.`);
|
|
2502
2558
|
return { ok: !issues.some((i) => i.severity === "error"), issues };
|
|
2503
2559
|
}
|
|
2504
2560
|
function withKeptIssues(check, before) {
|
|
2505
|
-
const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess',
|
|
2561
|
+
const had = new Set((_nullishCoalesce(_optionalChain([before, 'optionalAccess', _91 => _91.issues]), () => ( []))).filter((i) => i.severity === "error").map((i) => i.facet));
|
|
2506
2562
|
const kept = check.issues.filter((i) => i.severity === "error" && had.has(i.facet));
|
|
2507
2563
|
const issues = check.issues.filter((i) => !kept.includes(i));
|
|
2508
2564
|
return { ok: !issues.some((i) => i.severity === "error"), issues, kept };
|
|
@@ -2574,6 +2630,9 @@ function degrade(brush, profile, options = {}) {
|
|
|
2574
2630
|
case "iridescence":
|
|
2575
2631
|
delete b.iridescence;
|
|
2576
2632
|
break;
|
|
2633
|
+
case "ferro":
|
|
2634
|
+
delete b.ferro;
|
|
2635
|
+
break;
|
|
2577
2636
|
case "motion":
|
|
2578
2637
|
delete b.motion;
|
|
2579
2638
|
break;
|
|
@@ -2598,7 +2657,7 @@ function degrade(brush, profile, options = {}) {
|
|
|
2598
2657
|
}
|
|
2599
2658
|
dropped.push(issue);
|
|
2600
2659
|
}
|
|
2601
|
-
if (_optionalChain([b, 'access',
|
|
2660
|
+
if (_optionalChain([b, 'access', _92 => _92.behaviour, 'optionalAccess', _93 => _93.exchange]) && !Object.keys(b.behaviour.exchange).length) delete b.behaviour.exchange;
|
|
2602
2661
|
if (b.colour && !Object.keys(b.colour).length) delete b.colour;
|
|
2603
2662
|
const after = checkBrush(b, profile).issues.filter((i) => i.severity === "error");
|
|
2604
2663
|
return { brush: b, dropped, issues: after };
|
|
@@ -2642,7 +2701,7 @@ function parseBrushLibrary2(raw, problems = []) {
|
|
|
2642
2701
|
if (file && file.version !== void 0 && file.version !== 1 && file.version !== 2) {
|
|
2643
2702
|
throw new BrushLibraryError("invalid", `Brush library version ${JSON.stringify(file.version)} is not supported; this library reads versions 1 and 2.`);
|
|
2644
2703
|
}
|
|
2645
|
-
const v1File = _optionalChain([file, 'optionalAccess',
|
|
2704
|
+
const v1File = _optionalChain([file, 'optionalAccess', _94 => _94.version]) === 1;
|
|
2646
2705
|
const out = [];
|
|
2647
2706
|
items.forEach((item, i) => {
|
|
2648
2707
|
const at = `brushes[${i}]`;
|
|
@@ -2903,7 +2962,7 @@ function snapshotBrushLibrary(library, onChange) {
|
|
|
2903
2962
|
(list2) => {
|
|
2904
2963
|
entries = list2;
|
|
2905
2964
|
user = list2.filter((e) => !e.builtin).map((e) => e.brush);
|
|
2906
|
-
_optionalChain([onChange, 'optionalCall',
|
|
2965
|
+
_optionalChain([onChange, 'optionalCall', _95 => _95()]);
|
|
2907
2966
|
},
|
|
2908
2967
|
() => void 0
|
|
2909
2968
|
);
|
|
@@ -3045,4 +3104,6 @@ function snapshotBrushLibrary(library, onChange) {
|
|
|
3045
3104
|
|
|
3046
3105
|
|
|
3047
3106
|
|
|
3048
|
-
|
|
3107
|
+
|
|
3108
|
+
|
|
3109
|
+
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.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;
|
|
@@ -27,7 +27,8 @@ var _chunkPFHJS4HEcjs = require('./chunk-PFHJS4HE.cjs');
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
|
|
31
|
+
var _chunkHRUK5TFWcjs = require('./chunk-HRUK5TFW.cjs');
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
var _chunkW5M3J7PVcjs = require('./chunk-W5M3J7PV.cjs');
|
|
@@ -38,13 +39,20 @@ var _chunkXFM3OCHUcjs = require('./chunk-XFM3OCHU.cjs');
|
|
|
38
39
|
// src/brushes/patch.ts
|
|
39
40
|
var isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
40
41
|
var copy = (v) => JSON.parse(JSON.stringify(v));
|
|
41
|
-
var FACETS =
|
|
42
|
+
var FACETS = _chunkHRUK5TFWcjs.BRUSH_JSON_SCHEMA.properties;
|
|
42
43
|
var BRUSH_PATCH_PROPERTIES = (() => {
|
|
43
44
|
const { id: _id, name: _name, ...rest } = FACETS;
|
|
44
45
|
const { required: _r, ...tip } = rest.tip;
|
|
45
|
-
|
|
46
|
+
const ferro = {
|
|
47
|
+
description: "Liquid ferrofluid paint: 0..1 (amount), or { amount, wavelength, threshold }. Rises into glossy Rosensweig spikes near magnets until cured.",
|
|
48
|
+
anyOf: [
|
|
49
|
+
{ type: "number", minimum: 0, maximum: 1, description: "How much liquid ferrofluid the brush lays per dab (0..1)." },
|
|
50
|
+
_chunkHRUK5TFWcjs.BRUSH_FACET_SCHEMAS.ferro
|
|
51
|
+
]
|
|
52
|
+
};
|
|
53
|
+
return { ...rest, tip: { ...tip, description: `${tip.description} In a patch, shape may be left out to keep it.` }, ferro };
|
|
46
54
|
})();
|
|
47
|
-
var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "motion", "livePatterns", "colour"];
|
|
55
|
+
var UNSETTABLE_BRUSH_FACETS = ["description", "tags", "medium", "variety", "marks", "dynamics", "behaviour", "light", "fluorescence", "thermochromic", "iridescence", "ghost", "mutation", "ferro", "motion", "livePatterns", "colour"];
|
|
48
56
|
var BRUSH_UNSET_PROPERTY = {
|
|
49
57
|
type: "array",
|
|
50
58
|
minItems: 1,
|
|
@@ -54,9 +62,11 @@ var BRUSH_UNSET_PROPERTY = {
|
|
|
54
62
|
};
|
|
55
63
|
function mergeBrushPatch(base, patch, path = "") {
|
|
56
64
|
const out = { ...base };
|
|
57
|
-
for (const [k,
|
|
58
|
-
if (
|
|
59
|
-
const
|
|
65
|
+
for (const [k, rawV] of Object.entries(patch)) {
|
|
66
|
+
if (rawV === void 0) continue;
|
|
67
|
+
const v = path === "" && k === "ferro" && typeof rawV === "number" ? { amount: rawV } : rawV;
|
|
68
|
+
const rawOld = out[k];
|
|
69
|
+
const old = path === "" && k === "ferro" && typeof rawOld === "number" ? { amount: rawOld } : rawOld;
|
|
60
70
|
const replaceMarks = path === "" && k === "marks" && isObject(old) && isObject(v) && old.kind !== v.kind;
|
|
61
71
|
out[k] = isObject(v) && isObject(old) && !replaceMarks ? mergeBrushPatch(old, v, `${path}${k}.`) : copy(v);
|
|
62
72
|
}
|
|
@@ -557,7 +567,7 @@ function idMaker(prefix) {
|
|
|
557
567
|
return (name) => {
|
|
558
568
|
const base = `${prefix}-${slug(name, 20) || "brush"}`.slice(0, 58).replace(/-+$/, "");
|
|
559
569
|
let id = base;
|
|
560
|
-
for (let n = 2; used.has(id) || !
|
|
570
|
+
for (let n = 2; used.has(id) || !_chunkHRUK5TFWcjs.BRUSH_ID.test(id); n++) id = `${base}-${n}`;
|
|
561
571
|
used.add(id);
|
|
562
572
|
return id;
|
|
563
573
|
};
|
|
@@ -582,9 +592,9 @@ function readAbrPack(bytes, name, prefix, licence, pack) {
|
|
|
582
592
|
return;
|
|
583
593
|
}
|
|
584
594
|
try {
|
|
585
|
-
const source =
|
|
595
|
+
const source = _chunkHRUK5TFWcjs.brushSourceFromMask.call(void 0, { id: `${brushId}-shape`, name: label, licence, origin: `${name}.abr` }, tip.width, tip.height, tip.mask);
|
|
586
596
|
pack.sources.push(source);
|
|
587
|
-
pack.brushes.push({ ...base, tip: { shape: "stamp", size: clamp2(Math.max(tip.width, tip.height), 1, 2500), spacing: _nullishCoalesce(tip.spacing, () => ( 0.25)), stamps: [
|
|
597
|
+
pack.brushes.push({ ...base, tip: { shape: "stamp", size: clamp2(Math.max(tip.width, tip.height), 1, 2500), spacing: _nullishCoalesce(tip.spacing, () => ( 0.25)), stamps: [_chunkHRUK5TFWcjs.brushSourceRef.call(void 0, source.id)] } });
|
|
588
598
|
} catch (e) {
|
|
589
599
|
pack.unsupported.push(`"${label}": ${e.message}`);
|
|
590
600
|
}
|
|
@@ -626,7 +636,7 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
|
|
|
626
636
|
const e = byName.get(`${dir}${file}`);
|
|
627
637
|
if (!e) return null;
|
|
628
638
|
try {
|
|
629
|
-
const s =
|
|
639
|
+
const s = _chunkHRUK5TFWcjs.makeBrushSource.call(void 0, { id: `${brushId}-${kind}`, name: `${label} ${kind}`, image: e.read(), channel: "lightness", licence: [licence, terms].filter(Boolean).join("\n\n") || void 0, origin: `${where}/${file}` });
|
|
630
640
|
pack.sources.push(s);
|
|
631
641
|
return s;
|
|
632
642
|
} catch (err) {
|
|
@@ -647,8 +657,8 @@ function readProcreatePack(bytes, name, prefix, licence, pack) {
|
|
|
647
657
|
shape: shape ? "stamp" : "round",
|
|
648
658
|
size: 40,
|
|
649
659
|
...plot !== void 0 ? { spacing: plot } : {},
|
|
650
|
-
...shape ? { stamps: [
|
|
651
|
-
...grain ? { grain: { source:
|
|
660
|
+
...shape ? { stamps: [_chunkHRUK5TFWcjs.brushSourceRef.call(void 0, shape.id)] } : {},
|
|
661
|
+
...grain ? { grain: { source: _chunkHRUK5TFWcjs.brushSourceRef.call(void 0, grain.id), mode: "moving" } } : {}
|
|
652
662
|
}
|
|
653
663
|
});
|
|
654
664
|
if (!settings) pack.unsupported.push(`"${label}": its Brush.archive could not be read; the brush takes its name from the file and default settings.`);
|
|
@@ -702,17 +712,17 @@ async function importBrushFile(library, file, options = {}) {
|
|
|
702
712
|
// src/brushes/tools.ts
|
|
703
713
|
var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
|
|
704
714
|
var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
705
|
-
var FACETS2 =
|
|
715
|
+
var FACETS2 = _chunkHRUK5TFWcjs.BRUSH_JSON_SCHEMA.properties;
|
|
706
716
|
var ID = { type: "string", pattern: String(FACETS2.id.pattern), description: "Brush id from list_brush_presets (lowercase letters, digits and dashes)." };
|
|
707
717
|
var FACET_PROPS = BRUSH_PATCH_PROPERTIES;
|
|
708
|
-
var HOSTS = Object.keys(
|
|
718
|
+
var HOSTS = Object.keys(_chunkHRUK5TFWcjs.BRUSH_HOST_PROFILES);
|
|
709
719
|
var copy2 = (v) => JSON.parse(JSON.stringify(v));
|
|
710
720
|
var merge = mergeBrushPatch;
|
|
711
721
|
var changedPaths = changedBrushPaths;
|
|
712
722
|
function summary(entry, profile, withCheck) {
|
|
713
723
|
const b = entry.brush;
|
|
714
|
-
const engine =
|
|
715
|
-
const check = withCheck ?
|
|
724
|
+
const engine = _chunkHRUK5TFWcjs.resolveEngine.call(void 0, b);
|
|
725
|
+
const check = withCheck ? _chunkHRUK5TFWcjs.checkBrush.call(void 0, b, profile) : null;
|
|
716
726
|
return {
|
|
717
727
|
id: b.id,
|
|
718
728
|
name: b.name,
|
|
@@ -721,47 +731,48 @@ function summary(entry, profile, withCheck) {
|
|
|
721
731
|
...b.medium ? { medium: b.medium } : {},
|
|
722
732
|
...b.variety ? { variety: b.variety } : {},
|
|
723
733
|
...b.tool ? { tool: b.tool } : {},
|
|
724
|
-
category:
|
|
734
|
+
category: _chunkHRUK5TFWcjs.resolveCategory.call(void 0, b, engine),
|
|
725
735
|
engine,
|
|
726
736
|
tip: b.tip.shape,
|
|
727
737
|
...b.tip.size !== void 0 ? { size: b.tip.size } : {},
|
|
728
738
|
marks: _nullishCoalesce(_optionalChain([b, 'access', _16 => _16.marks, 'optionalAccess', _17 => _17.kind]), () => ( "continuous")),
|
|
729
739
|
surface: _nullishCoalesce(_optionalChain([b, 'access', _18 => _18.behaviour, 'optionalAccess', _19 => _19.surface]), () => ( "dry")),
|
|
730
740
|
..._optionalChain([b, 'access', _20 => _20.light, 'optionalAccess', _21 => _21.amount]) ? { light: b.light.amount } : {},
|
|
731
|
-
..._optionalChain([b, 'access', _22 => _22.
|
|
741
|
+
..._optionalChain([b, 'access', _22 => _22.ferro, 'optionalAccess', _23 => _23.amount]) ? { ferro: b.ferro.amount } : {},
|
|
742
|
+
..._optionalChain([b, 'access', _24 => _24.tags, 'optionalAccess', _25 => _25.length]) ? { tags: b.tags } : {},
|
|
732
743
|
...check ? { renderable: check.ok } : {}
|
|
733
744
|
};
|
|
734
745
|
}
|
|
735
746
|
var refusal = (check, host) => `${host.name} can't use this brush: ${check.issues.filter((i) => i.severity === "error").map((i) => `${i.facet}: ${i.reason} ${i.fix}`).join(" ")} (check_brush lists every issue; nothing was saved.)`;
|
|
736
747
|
var warnings = (check) => check.issues.filter((i) => i.severity === "warning");
|
|
737
748
|
function createBrushLibraryTools(library, options = {}) {
|
|
738
|
-
const profile = _nullishCoalesce(options.profile, () => (
|
|
749
|
+
const profile = _nullishCoalesce(options.profile, () => ( _chunkHRUK5TFWcjs.PAINT_PROFILE));
|
|
739
750
|
const hostOf = (id) => {
|
|
740
751
|
if (id === void 0) return profile;
|
|
741
|
-
const p =
|
|
742
|
-
if (!p) throw new (0,
|
|
752
|
+
const p = _chunkHRUK5TFWcjs.BRUSH_HOST_PROFILES[id];
|
|
753
|
+
if (!p) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", `No host "${id}"; use one of: ${HOSTS.join(", ")}.`);
|
|
743
754
|
return p;
|
|
744
755
|
};
|
|
745
756
|
const entry = async (id) => {
|
|
746
757
|
const found = await library.get(id);
|
|
747
758
|
if (found) return found;
|
|
748
759
|
const ids = (await library.list()).map((e) => e.brush.id);
|
|
749
|
-
throw new (0,
|
|
760
|
+
throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("unknown_brush", `No brush "${id}". ${_chunkHRUK5TFWcjs.closest.call(void 0, id, ids)}list_brush_presets lists them.`);
|
|
750
761
|
};
|
|
751
762
|
const checkFor = async (brush, p) => {
|
|
752
|
-
const check2 =
|
|
763
|
+
const check2 = _chunkHRUK5TFWcjs.checkBrush.call(void 0, brush, p);
|
|
753
764
|
const issues = [...check2.issues];
|
|
754
765
|
const refs = [...(_nullishCoalesce(brush.tip.stamps, () => ( []))).map((r) => ["tip.stamps", r]), ...brush.tip.grain ? [["tip.grain.source", brush.tip.grain.source]] : []];
|
|
755
766
|
for (const [facet, ref] of refs) {
|
|
756
|
-
const id =
|
|
767
|
+
const id = _chunkHRUK5TFWcjs.brushSourceIdOf.call(void 0, ref);
|
|
757
768
|
if (id === null || await library.getSource(id)) continue;
|
|
758
769
|
const ids = (await library.listSources()).map((x) => x.id);
|
|
759
|
-
issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${
|
|
770
|
+
issues.push({ facet, severity: "error", reason: `There is no image source "${id}" in the brush library. ${_chunkHRUK5TFWcjs.closest.call(void 0, id, ids)}`.trim(), fix: "Add it with add_brush_source, or use a ref list_brush_sources lists." });
|
|
760
771
|
}
|
|
761
|
-
const provider = _optionalChain([options, 'access',
|
|
772
|
+
const provider = _optionalChain([options, 'access', _26 => _26.stickers, 'optionalCall', _27 => _27()]);
|
|
762
773
|
if (!provider || brush.tip.shape !== "stamp") return { ok: !issues.some((i) => i.severity === "error"), issues };
|
|
763
774
|
for (const ref of _nullishCoalesce(brush.tip.stamps, () => ( []))) {
|
|
764
|
-
if (ref.startsWith("editor:") ||
|
|
775
|
+
if (ref.startsWith("editor:") || _chunkHRUK5TFWcjs.isBrushSourceRef.call(void 0, ref)) continue;
|
|
765
776
|
try {
|
|
766
777
|
await _chunkPFHJS4HEcjs.describeStickerRef.call(void 0, provider, ref);
|
|
767
778
|
} catch (e) {
|
|
@@ -774,12 +785,12 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
774
785
|
const problems = [];
|
|
775
786
|
let brush;
|
|
776
787
|
try {
|
|
777
|
-
brush =
|
|
788
|
+
brush = _chunkHRUK5TFWcjs.normalizeBrushSpec.call(void 0, raw, problems);
|
|
778
789
|
} catch (e) {
|
|
779
|
-
throw new (0,
|
|
790
|
+
throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", e.message);
|
|
780
791
|
}
|
|
781
|
-
const check2 =
|
|
782
|
-
if (!check2.ok) throw new (0,
|
|
792
|
+
const check2 = _chunkHRUK5TFWcjs.withKeptIssues.call(void 0, await checkFor(brush, profile), original ? await checkFor(original, profile) : null);
|
|
793
|
+
if (!check2.ok) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", refusal(check2, profile));
|
|
783
794
|
const saved = await library.save(brush, { overwrite });
|
|
784
795
|
return { ...saved, problems, check: check2 };
|
|
785
796
|
};
|
|
@@ -790,10 +801,10 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
790
801
|
inputSchema: {
|
|
791
802
|
type: "object",
|
|
792
803
|
properties: {
|
|
793
|
-
kind: { type: "string", enum: [...
|
|
794
|
-
medium: { type: "string", enum: [...
|
|
804
|
+
kind: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_KINDS], description: "mark (lays a material) or tool (works on paint already down)." },
|
|
805
|
+
medium: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_MEDIA], description: "Marks laying this medium." },
|
|
795
806
|
variety: { type: "string", maxLength: 40, description: "This variety (oil, watercolor, pencil, highlighter\u2026)." },
|
|
796
|
-
tool: { type: "string", enum: [...
|
|
807
|
+
tool: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_TOOLS], description: "Tools that do this." },
|
|
797
808
|
tag: { type: "string", maxLength: 40, description: "Brushes with this tag." },
|
|
798
809
|
text: { type: "string", maxLength: 200, description: "Words in the id, name, description, variety or tags (each word must match the start of one)." },
|
|
799
810
|
source: { type: "string", enum: ["all", "builtin", "user"], description: "all (default), builtin presets only, or user (saved) brushes only." },
|
|
@@ -820,8 +831,8 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
820
831
|
annotations: { title: "Describe a brush", ...READ },
|
|
821
832
|
handler: async ({ id }) => {
|
|
822
833
|
const e = await entry(id);
|
|
823
|
-
const engine =
|
|
824
|
-
return { brush: e.brush, builtin: e.builtin, engine, category:
|
|
834
|
+
const engine = _chunkHRUK5TFWcjs.resolveEngine.call(void 0, e.brush);
|
|
835
|
+
return { brush: e.brush, builtin: e.builtin, engine, category: _chunkHRUK5TFWcjs.resolveCategory.call(void 0, e.brush, engine), check: await checkFor(e.brush, profile) };
|
|
825
836
|
}
|
|
826
837
|
};
|
|
827
838
|
const check = {
|
|
@@ -839,20 +850,20 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
839
850
|
},
|
|
840
851
|
annotations: { title: "Check a brush for a host", ...READ },
|
|
841
852
|
handler: async ({ id, brush, host }) => {
|
|
842
|
-
if (id === void 0 === (brush === void 0)) throw new (0,
|
|
853
|
+
if (id === void 0 === (brush === void 0)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", "Give either id (a library brush) or brush (a spec), not both or neither.");
|
|
843
854
|
const p = hostOf(host);
|
|
844
855
|
let b;
|
|
845
856
|
const problems = [];
|
|
846
857
|
if (id !== void 0) b = (await entry(id)).brush;
|
|
847
858
|
else {
|
|
848
859
|
try {
|
|
849
|
-
b =
|
|
860
|
+
b = _chunkHRUK5TFWcjs.normalizeBrushSpec.call(void 0, brush, problems);
|
|
850
861
|
} catch (e) {
|
|
851
|
-
throw new (0,
|
|
862
|
+
throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", e.message);
|
|
852
863
|
}
|
|
853
864
|
}
|
|
854
865
|
const result = await checkFor(b, p);
|
|
855
|
-
return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded:
|
|
866
|
+
return { host: p.id, ...result, ...problems.length ? { problems } : {}, ...!result.ok ? { degraded: _chunkHRUK5TFWcjs.degrade.call(void 0, b, p) } : {} };
|
|
856
867
|
}
|
|
857
868
|
};
|
|
858
869
|
const exportTool = {
|
|
@@ -887,7 +898,7 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
887
898
|
});
|
|
888
899
|
const start = _nullishCoalesce(offset, () => ( 0));
|
|
889
900
|
const page = found.slice(start, start + (_nullishCoalesce(limit, () => ( 100))));
|
|
890
|
-
return { total: found.length, sources: page.map((x) => ({ ...
|
|
901
|
+
return { total: found.length, sources: page.map((x) => ({ ..._chunkHRUK5TFWcjs.summarizeBrushSource.call(void 0, x), usedBy: brushes.filter((b) => _chunkHRUK5TFWcjs.brushSourceIds.call(void 0, b).includes(x.id)).map((b) => b.id) })) };
|
|
891
902
|
}
|
|
892
903
|
};
|
|
893
904
|
const tools = [list, describe, check, exportTool, listSources];
|
|
@@ -911,7 +922,7 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
911
922
|
annotations: { title: "Preview a brush", ...READ },
|
|
912
923
|
handler: async ({ id, width, height, color }) => {
|
|
913
924
|
const { brush } = await entry(id);
|
|
914
|
-
const own = typeof _optionalChain([brush, 'access',
|
|
925
|
+
const own = typeof _optionalChain([brush, 'access', _28 => _28.colour, 'optionalAccess', _29 => _29.default]) === "string" && /^#[0-9a-f]{6}/i.test(brush.colour.default) ? brush.colour.default.slice(0, 7) : void 0;
|
|
915
926
|
const w = _nullishCoalesce(width, () => ( 256));
|
|
916
927
|
const h = _nullishCoalesce(height, () => ( 96));
|
|
917
928
|
const image = await render(brush, { width: w, height: h, color: _nullishCoalesce(_nullishCoalesce(color, () => ( own)), () => ( "#1f2937")) });
|
|
@@ -938,12 +949,12 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
938
949
|
},
|
|
939
950
|
annotations: { title: "Save a new brush", ...WRITE },
|
|
940
951
|
handler: async ({ basedOn, ...spec }) => {
|
|
941
|
-
if (library.isBuiltin(spec.id)) throw new (0,
|
|
942
|
-
if (await library.get(spec.id)) throw new (0,
|
|
952
|
+
if (library.isBuiltin(spec.id)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("builtin", `"${spec.id}" is a built-in brush id; pick another id (or basedOn "${spec.id}" with a new id).`);
|
|
953
|
+
if (await library.get(spec.id)) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("exists", `A brush "${spec.id}" exists already; pick another id, or change it with update_brush.`);
|
|
943
954
|
const base = basedOn !== void 0 ? (await entry(basedOn)).brush : void 0;
|
|
944
955
|
const raw = base ? merge(base, spec) : spec;
|
|
945
956
|
const saved = await store(raw, false);
|
|
946
|
-
return { id: saved.brush.id, brush: saved.brush, engine:
|
|
957
|
+
return { id: saved.brush.id, brush: saved.brush, engine: _chunkHRUK5TFWcjs.resolveEngine.call(void 0, saved.brush), problems: saved.problems, warnings: warnings(saved.check) };
|
|
947
958
|
}
|
|
948
959
|
},
|
|
949
960
|
{
|
|
@@ -964,7 +975,7 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
964
975
|
annotations: { title: "Update a brush", ...WRITE, idempotentHint: true },
|
|
965
976
|
handler: async ({ id, unset, ...patch }) => {
|
|
966
977
|
const e = await entry(id);
|
|
967
|
-
if (e.builtin) throw new (0,
|
|
978
|
+
if (e.builtin) throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("builtin", `"${id}" is a built-in brush and can't be changed; duplicate_brush makes a copy you can change.`);
|
|
968
979
|
const base = copy2(e.brush);
|
|
969
980
|
for (const k of _nullishCoalesce(unset, () => ( []))) delete base[k];
|
|
970
981
|
const saved = await store(merge(base, { ...patch, id }), true, e.brush);
|
|
@@ -974,14 +985,14 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
974
985
|
{
|
|
975
986
|
name: "add_brush_source",
|
|
976
987
|
title: "Add a brush image source",
|
|
977
|
-
description: `Adds an image to the brush library as a source for image tips and image grain (as Procreate's shape and grain sources). The image is a PNG data: URL; the marks are read from its transparency, its dark parts (a scan of marks on paper) or its light parts (white on black), as channel says, and kept as a grey mask at most ${
|
|
988
|
+
description: `Adds an image to the brush library as a source for image tips and image grain (as Procreate's shape and grain sources). The image is a PNG data: URL; the marks are read from its transparency, its dark parts (a scan of marks on paper) or its light parts (white on black), as channel says, and kept as a grey mask at most ${_chunkHRUK5TFWcjs.MAX_BRUSH_SOURCE_SIZE} px on a side. Returns id, ref (source:<id>), the stored source's width and height, problems (the channel auto picked, scaling) and replaced. Then make the brush: create_brush or update_brush with tip { shape: "stamp", stamps: [ref] } for an image tip, or tip.grain { source: ref } for grain. A taken id is refused unless overwrite.`,
|
|
978
989
|
inputSchema: {
|
|
979
990
|
type: "object",
|
|
980
991
|
properties: {
|
|
981
992
|
name: { type: "string", minLength: 1, maxLength: 80, description: 'Display name, e.g. "Charcoal scan".' },
|
|
982
|
-
image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${
|
|
993
|
+
image: { type: "string", pattern: "^data:image/png;base64,", maxLength: 4e7, description: `The image: a PNG data: URL, at most ${_chunkHRUK5TFWcjs.MAX_BRUSH_SOURCE_INPUT_PIXELS} pixels; larger than ${_chunkHRUK5TFWcjs.MAX_BRUSH_SOURCE_SIZE} px it is scaled down.` },
|
|
983
994
|
id: { type: "string", pattern: String(FACETS2.id.pattern), description: "The source id (default: from the name, made unique): lowercase letters, digits and dashes." },
|
|
984
|
-
channel: { type: "string", enum: [...
|
|
995
|
+
channel: { type: "string", enum: [..._chunkHRUK5TFWcjs.BRUSH_SOURCE_CHANNELS], description: "Where the marks are: auto (default: the transparency when the image has any, else the dark parts), alpha, darkness (dark marks on light paper) or lightness (light marks on black)." },
|
|
985
996
|
invert: { type: "boolean", description: "Swap painted and empty parts (default false)." },
|
|
986
997
|
licence: { type: "string", maxLength: 2e3, description: "The licence or terms the image came with, kept with the source." },
|
|
987
998
|
origin: { type: "string", maxLength: 200, description: "Where it came from: a file name, a pack or a URL." },
|
|
@@ -993,7 +1004,7 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
993
1004
|
annotations: { title: "Add a brush image source", ...WRITE },
|
|
994
1005
|
handler: async ({ overwrite, ...input }) => {
|
|
995
1006
|
const r = await library.addSource(input, { overwrite: !!overwrite });
|
|
996
|
-
return { id: r.source.id, ref:
|
|
1007
|
+
return { id: r.source.id, ref: _chunkHRUK5TFWcjs.brushSourceRef.call(void 0, r.source.id), width: r.source.width, height: r.source.height, problems: r.problems, replaced: r.replaced };
|
|
997
1008
|
}
|
|
998
1009
|
},
|
|
999
1010
|
{
|
|
@@ -1067,24 +1078,24 @@ function createBrushLibraryTools(library, options = {}) {
|
|
|
1067
1078
|
try {
|
|
1068
1079
|
bytes = _chunkW5M3J7PVcjs.base64ToBytes.call(void 0, file.replace(/^data:[^,]*,/, ""));
|
|
1069
1080
|
} catch (e6) {
|
|
1070
|
-
throw new (0,
|
|
1081
|
+
throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", "file is not base64: pass the pack's bytes as base64 (a data: URL works too).");
|
|
1071
1082
|
}
|
|
1072
1083
|
let r;
|
|
1073
1084
|
try {
|
|
1074
1085
|
r = await importBrushPack(library, bytes, { fileName, ...format ? { format } : {}, ...prefix ? { prefix } : {}, ...licence ? { licence } : {}, overwrite: !!overwrite });
|
|
1075
1086
|
} catch (e) {
|
|
1076
|
-
if (e instanceof
|
|
1077
|
-
throw new (0,
|
|
1087
|
+
if (e instanceof _chunkHRUK5TFWcjs.BrushLibraryError) throw e;
|
|
1088
|
+
throw new (0, _chunkHRUK5TFWcjs.BrushLibraryError)("invalid", `${e.message} Nothing was imported.`);
|
|
1078
1089
|
}
|
|
1079
1090
|
const entries = await Promise.all(r.brushes.map((b) => library.get(b.id)));
|
|
1080
|
-
return { ...r, brushes: r.brushes.map((b, i) => ({ ...b, renderable: entries[i] ?
|
|
1091
|
+
return { ...r, brushes: r.brushes.map((b, i) => ({ ...b, renderable: entries[i] ? _chunkHRUK5TFWcjs.checkBrush.call(void 0, entries[i].brush, profile).ok : false })) };
|
|
1081
1092
|
}
|
|
1082
1093
|
}
|
|
1083
1094
|
);
|
|
1084
1095
|
return tools;
|
|
1085
1096
|
}
|
|
1086
1097
|
function createBrushLibraryToolProvider(library, options = {}) {
|
|
1087
|
-
const profile = _nullishCoalesce(options.profile, () => (
|
|
1098
|
+
const profile = _nullishCoalesce(options.profile, () => ( _chunkHRUK5TFWcjs.PAINT_PROFILE));
|
|
1088
1099
|
const tools = createBrushLibraryTools(library, options);
|
|
1089
1100
|
return {
|
|
1090
1101
|
id: _nullishCoalesce(options.id, () => ( "brushes")),
|
|
@@ -1135,7 +1146,7 @@ function brushEngineControls(brush) {
|
|
|
1135
1146
|
const c = engineControls(brush);
|
|
1136
1147
|
if (!c) return null;
|
|
1137
1148
|
const mut = brush.mutation ? MUTATION_SLIDERS : [];
|
|
1138
|
-
const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access',
|
|
1149
|
+
const wetPaint = brush.engine === "wet" && _optionalChain([brush, 'access', _30 => _30.wet, 'optionalAccess', _31 => _31.tool]) === "paint" && !brush.ghost && !brush.mutation;
|
|
1139
1150
|
if (!(wetPaint || ["dab", "mixer", "particle", "bristle", "impasto"].includes(brush.engine))) {
|
|
1140
1151
|
return mut.length ? { ...c, sliders: [...c.sliders, ...mut] } : c;
|
|
1141
1152
|
}
|
|
@@ -1221,7 +1232,7 @@ function engineControls(brush) {
|
|
|
1221
1232
|
impastoTool: true
|
|
1222
1233
|
};
|
|
1223
1234
|
case "wet": {
|
|
1224
|
-
const tool = _nullishCoalesce(_optionalChain([brush, 'access',
|
|
1235
|
+
const tool = _nullishCoalesce(_optionalChain([brush, 'access', _32 => _32.wet, 'optionalAccess', _33 => _33.tool]), () => ( "paint"));
|
|
1225
1236
|
const ghost = tool === "paint" && (Boolean(brush.ghost) || Boolean(brush.mutation));
|
|
1226
1237
|
const sliders = tool === "paint" ? [
|
|
1227
1238
|
{ path: "wet.water", label: "Water", min: 0, max: 1, step: 0.01 },
|
|
@@ -74,7 +74,7 @@ function profileAlongPolyline(points, values, count = 32) {
|
|
|
74
74
|
var round3 = (v) => Math.round(v * 1e3) / 1e3;
|
|
75
75
|
var loading = null;
|
|
76
76
|
function loadCanvasBrushstrokeRenderer() {
|
|
77
|
-
loading ??= import("./brushstrokeRender-
|
|
77
|
+
loading ??= import("./brushstrokeRender-EIK3625T.js").catch((error) => {
|
|
78
78
|
loading = null;
|
|
79
79
|
throw error;
|
|
80
80
|
});
|