@pixerate/editor 0.279.0 → 0.280.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/{chunk-MITQGHN3.cjs → chunk-4BMRQSPB.cjs} +15 -1
- package/dist/{chunk-DWPFGWW5.js → chunk-FKO3CY2C.js} +1 -1
- package/dist/{chunk-N4MCWQZ7.js → chunk-HN57I7KT.js} +1 -1
- package/dist/{chunk-4NZTK7LM.cjs → chunk-K4ANWBF7.cjs} +35 -35
- package/dist/{chunk-VNF7A2JA.cjs → chunk-MNHP3AQT.cjs} +23 -23
- package/dist/{chunk-FNIWHSLI.js → chunk-NJDEKU5D.js} +1 -1
- package/dist/{chunk-CTHWXW5M.js → chunk-V6LQND7D.js} +14 -0
- package/dist/{chunk-QBZEC2JJ.cjs → chunk-WCC4NXWY.cjs} +86 -86
- package/dist/{chunk-PEQWARCP.cjs → chunk-WZYRYYXN.cjs} +29 -25
- package/dist/{chunk-HHX7ST6Z.js → chunk-YOM76H2V.js} +7 -3
- package/dist/image-editor/index.cjs +783 -783
- package/dist/image-editor/index.js +4 -4
- package/dist/paint/index.cjs +2 -2
- package/dist/paint/index.js +1 -1
- package/dist/paint/wet/gpu.d.cts +2 -0
- package/dist/paint/wet/gpu.d.ts +2 -0
- package/dist/paint-editor/index.cjs +128 -128
- package/dist/paint-editor/index.js +3 -3
- package/dist/vector/commands.d.cts +25 -0
- package/dist/vector/commands.d.ts +25 -0
- package/dist/vector/index.cjs +1056 -1034
- package/dist/vector/index.js +65 -43
- package/package.json +5 -5
- package/skills/pixerate-vector/SKILL.md +1 -1
package/dist/vector/index.js
CHANGED
|
@@ -35,7 +35,7 @@ import {
|
|
|
35
35
|
traceField,
|
|
36
36
|
traceVectorImage,
|
|
37
37
|
vectorTraceContours
|
|
38
|
-
} from "../chunk-
|
|
38
|
+
} from "../chunk-HN57I7KT.js";
|
|
39
39
|
import {
|
|
40
40
|
rasterizeCoverage
|
|
41
41
|
} from "../chunk-ADMRNWR7.js";
|
|
@@ -66,7 +66,7 @@ import {
|
|
|
66
66
|
reverseMorphContour,
|
|
67
67
|
subpathToMorphContour,
|
|
68
68
|
turnMorphContour
|
|
69
|
-
} from "../chunk-
|
|
69
|
+
} from "../chunk-FKO3CY2C.js";
|
|
70
70
|
import {
|
|
71
71
|
DEFAULT_VECTOR_FONT,
|
|
72
72
|
IDENTITY_MATRIX,
|
|
@@ -556,7 +556,7 @@ import {
|
|
|
556
556
|
withVectorStrokes,
|
|
557
557
|
withVectorTargetPaint,
|
|
558
558
|
zigzagPaths
|
|
559
|
-
} from "../chunk-
|
|
559
|
+
} from "../chunk-YOM76H2V.js";
|
|
560
560
|
import {
|
|
561
561
|
snapshotBrushLibrary
|
|
562
562
|
} from "../chunk-PPDUCZZV.js";
|
|
@@ -597,7 +597,7 @@ import {
|
|
|
597
597
|
resolveEffectValues
|
|
598
598
|
} from "../chunk-MV7CYFMJ.js";
|
|
599
599
|
import "../chunk-V2ZCJRDM.js";
|
|
600
|
-
import "../chunk-
|
|
600
|
+
import "../chunk-V6LQND7D.js";
|
|
601
601
|
import "../chunk-J23JOHPR.js";
|
|
602
602
|
import {
|
|
603
603
|
GRAIN_PATTERNS
|
|
@@ -16551,17 +16551,72 @@ function createVectorCommands(controller, options = {}) {
|
|
|
16551
16551
|
}
|
|
16552
16552
|
}
|
|
16553
16553
|
];
|
|
16554
|
+
const resolveImage = options.resolveImage;
|
|
16555
|
+
const IMAGE_WHAT = resolveImage ? "an image (a PNG data URL, or a reference the editor loads)" : "a PNG (base64 data URL)";
|
|
16556
|
+
const IMAGE_PARAM = {
|
|
16557
|
+
type: "string",
|
|
16558
|
+
description: resolveImage ? `The image: a data:image/png;base64,\u2026 URL, or ${options.imageReferences ?? "an image URL"} (up to ${VECTOR_TRACE_MAX_PIXELS / 1e6} million pixels).` : "The image as a data:image/png;base64,\u2026 URL (up to 4 million pixels)."
|
|
16559
|
+
};
|
|
16560
|
+
const decodePngBytes = (bytes, what) => {
|
|
16561
|
+
if (!isPng(bytes)) fail(`${what} is not a PNG.`);
|
|
16562
|
+
try {
|
|
16563
|
+
return decodePng(bytes, { maxPixels: VECTOR_TRACE_MAX_PIXELS });
|
|
16564
|
+
} catch (e) {
|
|
16565
|
+
return fail(`The PNG could not be read: ${e.message}`);
|
|
16566
|
+
}
|
|
16567
|
+
};
|
|
16568
|
+
const fromResolved = (ref, resolved) => {
|
|
16569
|
+
if (!resolved || typeof resolved !== "object") return fail(`There is no image "${ref}".`);
|
|
16570
|
+
if ("image" in resolved && resolved.image) return resolved.image;
|
|
16571
|
+
if ("png" in resolved && typeof resolved.png === "string") {
|
|
16572
|
+
const parsed = parseDataUrl(resolved.png);
|
|
16573
|
+
if (!parsed) fail(`The image "${ref}" was loaded as something other than a PNG data URL.`);
|
|
16574
|
+
return decodePngBytes(parsed.bytes, `The image "${ref}"`);
|
|
16575
|
+
}
|
|
16576
|
+
if ("png" in resolved && resolved.png instanceof Uint8Array) return decodePngBytes(resolved.png, `The image "${ref}"`);
|
|
16577
|
+
return fail(`The image "${ref}" was loaded as nothing usable (expected { image } or { png }).`);
|
|
16578
|
+
};
|
|
16579
|
+
const withImage = (image, use) => {
|
|
16580
|
+
if (typeof image !== "string" || !image.trim()) fail("image is empty.");
|
|
16581
|
+
if (/^data:/i.test(image)) {
|
|
16582
|
+
const parsed = parseDataUrl(image);
|
|
16583
|
+
if (!parsed || !isPng(parsed.bytes)) fail(resolveImage ? "image must be a PNG data URL (data:image/png;base64,\u2026) or a reference to an image." : "image must be a PNG data URL (data:image/png;base64,\u2026).");
|
|
16584
|
+
return use(decodePngBytes(parsed.bytes, "image"));
|
|
16585
|
+
}
|
|
16586
|
+
if (!resolveImage) return fail("image must be a PNG data URL (data:image/png;base64,\u2026).");
|
|
16587
|
+
const ref = image.trim();
|
|
16588
|
+
const load = async () => {
|
|
16589
|
+
let resolved;
|
|
16590
|
+
try {
|
|
16591
|
+
resolved = await resolveImage(ref, { maxPixels: VECTOR_TRACE_MAX_PIXELS });
|
|
16592
|
+
} catch (e) {
|
|
16593
|
+
return fail(`The image "${ref}" could not be loaded: ${e instanceof Error ? e.message : String(e)}`);
|
|
16594
|
+
}
|
|
16595
|
+
return use(fromResolved(ref, resolved));
|
|
16596
|
+
};
|
|
16597
|
+
return load();
|
|
16598
|
+
};
|
|
16599
|
+
const imageResult = (r) => {
|
|
16600
|
+
check2(r);
|
|
16601
|
+
return {
|
|
16602
|
+
id: r.id,
|
|
16603
|
+
paths: r.ids.map((id) => {
|
|
16604
|
+
const n2 = controller.getNode(id);
|
|
16605
|
+
return { id, name: n2.name, fill: n2.fill, subpaths: n2.subpaths.length };
|
|
16606
|
+
})
|
|
16607
|
+
};
|
|
16608
|
+
};
|
|
16554
16609
|
const traceCommands = () => [
|
|
16555
16610
|
{
|
|
16556
16611
|
...base,
|
|
16557
16612
|
id: `${prefix}traceImage`,
|
|
16558
16613
|
label: "Image Trace\u2026",
|
|
16559
16614
|
keywords: ["trace", "image trace", "live trace", "vectorize", "bitmap to vector", "png to svg", "autotrace", "posterize"],
|
|
16560
|
-
description: "Traces
|
|
16615
|
+
description: "Traces " + IMAGE_WHAT + " into vector paths and adds them as one group: `threshold` mode makes one even-odd path where the image is dark (or opaque with channel alpha); `color` mode makes a stacked path per colour (median-cut to `colors`, the most common at the bottom). Placed with its top-left at x, y and `width` wide (default one unit per pixel). One undo step. Returns { id, paths: [{ id, name, fill, subpaths }] }.",
|
|
16561
16616
|
params: {
|
|
16562
16617
|
type: "object",
|
|
16563
16618
|
properties: {
|
|
16564
|
-
image:
|
|
16619
|
+
image: IMAGE_PARAM,
|
|
16565
16620
|
mode: { type: "string", enum: ["threshold", "color"], description: "threshold (one colour, default) or color (a path per colour)." },
|
|
16566
16621
|
channel: { type: "string", enum: ["luminance", "alpha"], description: "Threshold mode: trace dark pixels (luminance, default) or opaque ones (alpha)." },
|
|
16567
16622
|
threshold: { type: "number", minimum: 0, maximum: 1, description: "Threshold mode: inside where darkness (or alpha) reaches this (default 0.5)." },
|
|
@@ -16581,61 +16636,28 @@ function createVectorCommands(controller, options = {}) {
|
|
|
16581
16636
|
undoable: true,
|
|
16582
16637
|
run: (_ctx, params) => {
|
|
16583
16638
|
const { image, ...options2 } = params;
|
|
16584
|
-
|
|
16585
|
-
if (!parsed || !isPng(parsed.bytes)) fail("image must be a PNG data URL (data:image/png;base64,\u2026).");
|
|
16586
|
-
let decoded2;
|
|
16587
|
-
try {
|
|
16588
|
-
decoded2 = decodePng(parsed.bytes, { maxPixels: VECTOR_TRACE_MAX_PIXELS });
|
|
16589
|
-
} catch (e) {
|
|
16590
|
-
return fail(`The PNG could not be read: ${e.message}`);
|
|
16591
|
-
}
|
|
16592
|
-
const r = controller.traceImage(decoded2, options2);
|
|
16593
|
-
check2(r);
|
|
16594
|
-
return {
|
|
16595
|
-
id: r.id,
|
|
16596
|
-
paths: r.ids.map((id) => {
|
|
16597
|
-
const n2 = controller.getNode(id);
|
|
16598
|
-
return { id, name: n2.name, fill: n2.fill, subpaths: n2.subpaths.length };
|
|
16599
|
-
})
|
|
16600
|
-
};
|
|
16639
|
+
return withImage(image, (pixels) => imageResult(controller.traceImage(pixels, options2)));
|
|
16601
16640
|
}
|
|
16602
16641
|
}
|
|
16603
16642
|
];
|
|
16604
16643
|
const IMAGE_PLACE = {
|
|
16605
|
-
image: { type: "string", description: "The picture as a data:image/png;base64,\u2026 URL (up to 4 million pixels)." },
|
|
16644
|
+
image: resolveImage ? IMAGE_PARAM : { type: "string", description: "The picture as a data:image/png;base64,\u2026 URL (up to 4 million pixels)." },
|
|
16606
16645
|
x: { type: "number", description: "Left edge in document units (default 0)." },
|
|
16607
16646
|
y: { type: "number", description: "Top edge in document units (default 0)." },
|
|
16608
16647
|
width: { type: "number", exclusiveMinimum: 0, description: "Width in document units (default: the image width in pixels)." },
|
|
16609
16648
|
name: { type: "string", description: "Group name (default: the style's name)." }
|
|
16610
16649
|
};
|
|
16611
|
-
const decodeImage = (image) => {
|
|
16612
|
-
const parsed = parseDataUrl(image);
|
|
16613
|
-
if (!parsed || !isPng(parsed.bytes)) fail("image must be a PNG data URL (data:image/png;base64,\u2026).");
|
|
16614
|
-
try {
|
|
16615
|
-
return decodePng(parsed.bytes, { maxPixels: VECTOR_TRACE_MAX_PIXELS });
|
|
16616
|
-
} catch (e) {
|
|
16617
|
-
return fail(`The PNG could not be read: ${e.message}`);
|
|
16618
|
-
}
|
|
16619
|
-
};
|
|
16620
16650
|
const stylize = (style, label2, keywords, description, props) => ({
|
|
16621
16651
|
...base,
|
|
16622
16652
|
id: `${prefix}${style}Image`,
|
|
16623
16653
|
label: label2,
|
|
16624
16654
|
keywords: ["stylize", "stylise", "bitmap to vector", "artistic", "png to svg", ...keywords],
|
|
16625
|
-
description: `${description} Added as one group placed with its top-left at x, y and width wide; colours of one kind share a compound path. One undo step. Returns { id, paths: [{ id, name, fill, subpaths }] }.`,
|
|
16655
|
+
description: `${resolveImage ? description.replace("a PNG", IMAGE_WHAT) : description} Added as one group placed with its top-left at x, y and width wide; colours of one kind share a compound path. One undo step. Returns { id, paths: [{ id, name, fill, subpaths }] }.`,
|
|
16626
16656
|
params: { type: "object", properties: { ...IMAGE_PLACE, ...props }, required: ["image"], additionalProperties: false },
|
|
16627
16657
|
undoable: true,
|
|
16628
16658
|
run: (_ctx, params) => {
|
|
16629
16659
|
const { image, ...options2 } = params;
|
|
16630
|
-
|
|
16631
|
-
check2(r);
|
|
16632
|
-
return {
|
|
16633
|
-
id: r.id,
|
|
16634
|
-
paths: r.ids.map((id) => {
|
|
16635
|
-
const n2 = controller.getNode(id);
|
|
16636
|
-
return { id, name: n2.name, fill: n2.fill, subpaths: n2.subpaths.length };
|
|
16637
|
-
})
|
|
16638
|
-
};
|
|
16660
|
+
return withImage(image, (pixels) => imageResult(controller.stylizeImage(pixels, style, options2)));
|
|
16639
16661
|
}
|
|
16640
16662
|
});
|
|
16641
16663
|
const CELL = (dflt, what) => ({ type: "number", minimum: 1, description: `${what} in image pixels (default ${dflt}); larger draws fewer, bigger shapes.` });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixerate/editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.280.0",
|
|
4
4
|
"description": "UI-agnostic rich text and media editing core library",
|
|
5
5
|
"author": "Pixerate",
|
|
6
6
|
"license": "MIT",
|
|
@@ -494,7 +494,7 @@
|
|
|
494
494
|
],
|
|
495
495
|
"sideEffects": false,
|
|
496
496
|
"devDependencies": {
|
|
497
|
-
"@anthropic-ai/sdk": "1.
|
|
497
|
+
"@anthropic-ai/sdk": "1.6.0",
|
|
498
498
|
"@dagrejs/dagre": "^1.1.8",
|
|
499
499
|
"@tiptap/core": "^2.27.3",
|
|
500
500
|
"@tiptap/extension-character-count": "^2.27.3",
|
|
@@ -521,17 +521,17 @@
|
|
|
521
521
|
"@tiptap/suggestion": "^2.27.3",
|
|
522
522
|
"@types/dagre": "^0.7.54",
|
|
523
523
|
"@types/markdown-it": "^14.2.0",
|
|
524
|
-
"@types/node": "^26.6.
|
|
524
|
+
"@types/node": "^26.6.6",
|
|
525
525
|
"assemblyscript": "0.28.20",
|
|
526
526
|
"fast-check": "^4.10.2",
|
|
527
527
|
"markdown-it": "^15.0.3",
|
|
528
528
|
"markdown-it-task-lists": "^2.1.1",
|
|
529
|
-
"mermaid": "12.
|
|
529
|
+
"mermaid": "12.3.0",
|
|
530
530
|
"prosemirror-markdown": "^1.13.9",
|
|
531
531
|
"tiptap-markdown": "^0.8.10",
|
|
532
532
|
"tsup": "^9.0.0",
|
|
533
533
|
"typescript": "^5.7.3",
|
|
534
|
-
"vitest": "^5.0
|
|
534
|
+
"vitest": "^5.1.0",
|
|
535
535
|
"@pixerate/markdown-conformance": "0.2.0"
|
|
536
536
|
},
|
|
537
537
|
"peerDependencies": {
|
|
@@ -131,7 +131,7 @@ the pitfalls, and uses the commands below.
|
|
|
131
131
|
|
|
132
132
|
| Command | Use it to |
|
|
133
133
|
| --- | --- |
|
|
134
|
-
| `vector.traceImage` | Turn a PNG (data URL) into vector paths in one group: `threshold` mode for one-colour art (logos, scans, silhouettes; `channel: "alpha"` for cut-outs), `color` mode for a stacked path per colour (`colors` 2–32). Raise `tolerance` for fewer anchors, `cornerRoundness` 0 for sharp polygons. Place it with `x`, `y`, `width`. Returns `{ id, paths }`; check `subpaths` counts and simplify or delete specks after. |
|
|
134
|
+
| `vector.traceImage` | Turn a PNG (data URL) into vector paths in one group, or an image the host loads by reference (its `image` description says which: a canvas image node's id, a URL); pass the reference instead of writing the image out: `threshold` mode for one-colour art (logos, scans, silhouettes; `channel: "alpha"` for cut-outs), `color` mode for a stacked path per colour (`colors` 2–32). Raise `tolerance` for fewer anchors, `cornerRoundness` 0 for sharp polygons. Place it with `x`, `y`, `width`. Returns `{ id, paths }`; check `subpaths` counts and simplify or delete specks after. |
|
|
135
135
|
| `vector.mosaicImage` | Stylise a PNG as mosaic tiles (`cell` px, `shape` square / circle, `gap`, `colors`): pixel art, tiled murals. Returns `{ id, paths }`, one compound path per colour. |
|
|
136
136
|
| `vector.halftoneImage` | Stylise a PNG as halftone dots on a turned screen (`cell`, `angle`, ink `color` or null for the picture's colours): comic and pop-art looks, print effects. |
|
|
137
137
|
| `vector.lowPolyImage` | Stylise a PNG as low-poly triangles (`cell`, `jitter`, `seed`, `colors`): geometric portraits and backdrops. |
|