@pixerate/editor 0.256.0 → 0.258.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.
Files changed (124) hide show
  1. package/dist/agent/index.cjs +40 -38
  2. package/dist/agent/index.js +9 -7
  3. package/dist/animation/index.cjs +4 -2
  4. package/dist/animation/index.js +4 -2
  5. package/dist/animation-editor/index.cjs +63 -61
  6. package/dist/animation-editor/index.js +7 -5
  7. package/dist/brushes/colour.d.cts +11 -0
  8. package/dist/brushes/colour.d.ts +11 -0
  9. package/dist/brushes/index.cjs +51 -30
  10. package/dist/brushes/index.d.cts +1 -0
  11. package/dist/brushes/index.d.ts +1 -0
  12. package/dist/brushes/index.js +25 -4
  13. package/dist/brushes/resolve.d.cts +2 -0
  14. package/dist/brushes/resolve.d.ts +2 -0
  15. package/dist/brushes/schema.d.cts +1 -0
  16. package/dist/brushes/schema.d.ts +1 -0
  17. package/dist/brushes/tools.d.cts +7 -0
  18. package/dist/brushes/tools.d.ts +7 -0
  19. package/dist/brushes/types.d.cts +10 -2
  20. package/dist/brushes/types.d.ts +10 -2
  21. package/dist/brushes/ui.d.cts +14 -3
  22. package/dist/brushes/ui.d.ts +14 -3
  23. package/dist/{brushstrokeRender-HCOQUSWW.js → brushstrokeRender-JI4W6F2G.js} +2 -2
  24. package/dist/{brushstrokeRender-ZZOXI5O5.cjs → brushstrokeRender-MQ6PSDM5.cjs} +11 -11
  25. package/dist/canvas/index.cjs +20 -18
  26. package/dist/canvas/index.js +7 -5
  27. package/dist/chart/index.cjs +159 -157
  28. package/dist/chart/index.js +9 -7
  29. package/dist/{chunk-7272D3K2.js → chunk-2EUW2XZX.js} +27 -276
  30. package/dist/{chunk-L6Y7TSQ4.js → chunk-2VJ6OVJV.js} +1 -1
  31. package/dist/{chunk-6ZZKRH7R.js → chunk-47V3WXDG.js} +2 -2
  32. package/dist/{chunk-H7ET2ISK.cjs → chunk-4IMD2TLY.cjs} +52 -52
  33. package/dist/{chunk-VUKUTT2W.js → chunk-4M4E3N6X.js} +1 -1
  34. package/dist/{chunk-TBAVCLEQ.cjs → chunk-5Q5MLXAD.cjs} +23 -23
  35. package/dist/{chunk-MONXNVZK.js → chunk-6I23ZCGK.js} +5 -3
  36. package/dist/{chunk-GOBOCZZI.js → chunk-6NQPKNUZ.js} +1 -1
  37. package/dist/{chunk-WYGSR3IJ.js → chunk-AORZ5M5C.js} +1 -1
  38. package/dist/chunk-AVTPZO4Z.cjs +142 -0
  39. package/dist/{chunk-WKMUBATU.js → chunk-C2WEIEUB.js} +1 -1
  40. package/dist/{chunk-P3K2JCJA.js → chunk-D5BXSOSU.js} +3 -3
  41. package/dist/chunk-E2V5DA3W.js +36 -0
  42. package/dist/{chunk-WZOGDKCQ.js → chunk-F7CPSRLN.js} +0 -133
  43. package/dist/chunk-FJBQTZS4.js +17 -0
  44. package/dist/{chunk-SOSBOS5T.cjs → chunk-G23BTQA5.cjs} +22 -22
  45. package/dist/{chunk-EUIDTZNQ.cjs → chunk-I3Y2Q3PM.cjs} +59 -308
  46. package/dist/{chunk-YHUMGBZD.js → chunk-ICTPLVSR.js} +22 -4
  47. package/dist/{chunk-LRNUZKWV.cjs → chunk-IPUTIUGQ.cjs} +1 -1
  48. package/dist/{chunk-6GRUVGKU.js → chunk-ITURMC2M.js} +3 -3
  49. package/dist/{chunk-HYWRU5VX.js → chunk-IXQZHCOF.js} +1 -1
  50. package/dist/chunk-J5UQHWVL.js +142 -0
  51. package/dist/{chunk-YBAPT7NL.js → chunk-JC2SHA4A.js} +1 -23
  52. package/dist/chunk-LRTR4ASZ.cjs +17 -0
  53. package/dist/{chunk-HUAISCUX.cjs → chunk-M2HG5DJ2.cjs} +18 -18
  54. package/dist/{chunk-N76AMOKE.cjs → chunk-MDLEGVEN.cjs} +42 -42
  55. package/dist/chunk-MEGSQUQO.cjs +36 -0
  56. package/dist/chunk-MLLTWAXH.cjs +276 -0
  57. package/dist/{chunk-RHPSE2YR.js → chunk-MQ6MGIQM.js} +2 -2
  58. package/dist/{chunk-PGPFWC35.cjs → chunk-MQGQTKVW.cjs} +51 -33
  59. package/dist/{chunk-5YWWQ36H.cjs → chunk-O3ZVZSNJ.cjs} +9 -9
  60. package/dist/{chunk-GCTUOTCW.cjs → chunk-P3PZ63M3.cjs} +35 -35
  61. package/dist/{chunk-WRZ6C4TU.cjs → chunk-P6WYDBTH.cjs} +4 -4
  62. package/dist/{chunk-CJ6TBL2N.cjs → chunk-RHEMMGCN.cjs} +16 -16
  63. package/dist/{chunk-HIMGBZAM.cjs → chunk-RSIKDWOP.cjs} +201 -38
  64. package/dist/{chunk-SABJMH6M.cjs → chunk-RVGP2XLF.cjs} +2 -135
  65. package/dist/{chunk-JVRLGV3C.js → chunk-SMTUQWGY.js} +184 -21
  66. package/dist/{chunk-DMTEQ6SH.js → chunk-SSFMWJDK.js} +4 -4
  67. package/dist/{chunk-TFF2GTGN.cjs → chunk-SXQHWXEL.cjs} +2 -24
  68. package/dist/{chunk-IWEVV63O.cjs → chunk-UEYLANO3.cjs} +18 -16
  69. package/dist/chunk-VR6OGHU5.js +276 -0
  70. package/dist/{chunk-AF23QK5F.js → chunk-YQ4PQTBB.js} +1 -1
  71. package/dist/{chunk-B7V34GIH.cjs → chunk-YSGW7VV4.cjs} +88 -88
  72. package/dist/{chunk-3NS5C7FB.cjs → chunk-YYBW6DF2.cjs} +76 -76
  73. package/dist/{chunk-UFEDHACQ.js → chunk-Z7BX4TWO.js} +2 -2
  74. package/dist/{chunk-RUONPPMC.cjs → chunk-ZSE25IZA.cjs} +8 -8
  75. package/dist/color/index.cjs +7 -3
  76. package/dist/color/index.js +18 -14
  77. package/dist/export/index.cjs +8 -6
  78. package/dist/export/index.js +7 -5
  79. package/dist/extensions/index.cjs +11 -9
  80. package/dist/extensions/index.js +10 -8
  81. package/dist/gradient/index.cjs +33 -31
  82. package/dist/gradient/index.js +5 -3
  83. package/dist/image-editor/brush-presets.d.cts +4 -1
  84. package/dist/image-editor/brush-presets.d.ts +4 -1
  85. package/dist/image-editor/controller.d.cts +10 -5
  86. package/dist/image-editor/controller.d.ts +10 -5
  87. package/dist/image-editor/index.cjs +1090 -1073
  88. package/dist/image-editor/index.js +37 -20
  89. package/dist/index.cjs +17 -15
  90. package/dist/index.js +11 -9
  91. package/dist/paint-editor/brushes.d.cts +18 -1
  92. package/dist/paint-editor/brushes.d.ts +18 -1
  93. package/dist/paint-editor/collaboration.d.cts +38 -0
  94. package/dist/paint-editor/collaboration.d.ts +38 -0
  95. package/dist/paint-editor/controller.d.cts +60 -0
  96. package/dist/paint-editor/controller.d.ts +60 -0
  97. package/dist/paint-editor/engine.d.cts +7 -0
  98. package/dist/paint-editor/engine.d.ts +7 -0
  99. package/dist/paint-editor/index.cjs +1564 -1324
  100. package/dist/paint-editor/index.js +1198 -958
  101. package/dist/paint-editor/mark-settings.d.cts +1 -1
  102. package/dist/paint-editor/mark-settings.d.ts +1 -1
  103. package/dist/paint-editor/procedural.d.cts +4 -2
  104. package/dist/paint-editor/procedural.d.ts +4 -2
  105. package/dist/paint-editor/stamp-tip.d.cts +45 -0
  106. package/dist/paint-editor/stamp-tip.d.ts +45 -0
  107. package/dist/paint-editor/stroke.d.cts +4 -0
  108. package/dist/paint-editor/stroke.d.ts +4 -0
  109. package/dist/stickers/index.cjs +4 -2
  110. package/dist/stickers/index.js +6 -4
  111. package/dist/typography/index.cjs +3 -2
  112. package/dist/typography/index.js +2 -1
  113. package/dist/vector/index.cjs +971 -969
  114. package/dist/vector/index.js +8 -6
  115. package/dist/video-editor/index.cjs +4 -2
  116. package/dist/video-editor/index.js +4 -2
  117. package/package.json +1 -1
  118. package/skills/pixerate-brushes/SKILL.md +21 -11
  119. package/skills/pixerate-brushes-design/SKILL.md +6 -2
  120. package/skills/pixerate-brushes-design/evals/canvas-chalk.json +8 -8
  121. package/skills/pixerate-canvas/SKILL.md +3 -2
  122. package/skills/pixerate-image-editor/SKILL.md +1 -1
  123. package/skills/pixerate-paint-editor/SKILL.md +5 -1
  124. package/skills/pixerate-vector/SKILL.md +1 -1
@@ -0,0 +1,276 @@
1
+ import {
2
+ formatHex,
3
+ normalizeColor,
4
+ toSrgbGamut
5
+ } from "./chunk-JC2SHA4A.js";
6
+ import {
7
+ contrastLevel,
8
+ contrastRatio,
9
+ oklabToOklch,
10
+ oklabToRgb,
11
+ oklchToOklab,
12
+ parseColor,
13
+ rgbToOklab
14
+ } from "./chunk-MHLU6GRJ.js";
15
+
16
+ // src/color/dual.ts
17
+ var DEFAULT_SCHEME_SURFACES = {
18
+ light: "#ffffff",
19
+ dark: "#0b0b0f"
20
+ };
21
+ var clamp = (v, min, max) => Math.min(max, Math.max(min, v));
22
+ function isDualColor(value) {
23
+ return typeof value === "object" && value !== null && typeof value.light === "string" && typeof value.dark === "string";
24
+ }
25
+ function parseDualColor(input) {
26
+ if (input === null || input === void 0) return null;
27
+ if (isDualColor(input)) {
28
+ if (parseColor(input.light) === null || parseColor(input.dark) === null) {
29
+ return null;
30
+ }
31
+ return { light: input.light, dark: input.dark };
32
+ }
33
+ if (typeof input === "string") {
34
+ const trimmed = input.trim();
35
+ if (trimmed.toLowerCase().startsWith("light-dark(") && trimmed.endsWith(")")) {
36
+ const inner = trimmed.slice("light-dark(".length, -1).trim();
37
+ if (inner.toLowerCase().includes("light-dark(")) {
38
+ return null;
39
+ }
40
+ let depth = 0;
41
+ let commaIndex = -1;
42
+ for (let i = 0; i < inner.length; i++) {
43
+ const char = inner[i];
44
+ if (char === "(") {
45
+ depth++;
46
+ } else if (char === ")") {
47
+ depth--;
48
+ if (depth < 0) return null;
49
+ } else if (char === "," && depth === 0) {
50
+ if (commaIndex !== -1) {
51
+ return null;
52
+ }
53
+ commaIndex = i;
54
+ }
55
+ }
56
+ if (depth !== 0 || commaIndex === -1) {
57
+ return null;
58
+ }
59
+ const lightPart = inner.slice(0, commaIndex).trim();
60
+ const darkPart = inner.slice(commaIndex + 1).trim();
61
+ if (!lightPart || !darkPart) return null;
62
+ if (parseColor(lightPart) === null || parseColor(darkPart) === null) {
63
+ return null;
64
+ }
65
+ return { light: lightPart, dark: darkPart };
66
+ }
67
+ if (parseColor(trimmed) !== null) {
68
+ return { light: trimmed, dark: trimmed };
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ function normalizeDualColor(input) {
74
+ const parsed = parseDualColor(input);
75
+ if (!parsed) return null;
76
+ const light = normalizeColor(parsed.light);
77
+ const dark = normalizeColor(parsed.dark);
78
+ if (!light || !dark) return null;
79
+ return { light, dark };
80
+ }
81
+ function resolveColor(value, scheme) {
82
+ const normalized = normalizeDualColor(value);
83
+ if (!normalized) return null;
84
+ return scheme === "dark" ? normalized.dark : normalized.light;
85
+ }
86
+ function formatDualColor(value) {
87
+ const light = normalizeColor(value.light) ?? value.light;
88
+ const dark = normalizeColor(value.dark) ?? value.dark;
89
+ if (light === dark) {
90
+ return light;
91
+ }
92
+ return `light-dark(${light}, ${dark})`;
93
+ }
94
+ function isSameInBothSchemes(value) {
95
+ const light = normalizeColor(value.light);
96
+ const dark = normalizeColor(value.dark);
97
+ if (!light || !dark) return value.light === value.dark;
98
+ return light === dark;
99
+ }
100
+ function setDualColorSide(value, scheme, color) {
101
+ const base = normalizeDualColor(value) ?? { light: "#000000", dark: "#000000" };
102
+ const normColor = normalizeColor(color) ?? color;
103
+ return {
104
+ light: scheme === "light" ? normColor : base.light,
105
+ dark: scheme === "dark" ? normColor : base.dark
106
+ };
107
+ }
108
+ function deriveDualColor(color, options) {
109
+ const fromScheme = options?.from ?? "light";
110
+ const baseRgba = parseColor(color);
111
+ if (!baseRgba) {
112
+ throw new Error(`"${String(color)}" is not a colour; pass hex, rgb(), hsl(), oklch() or a CSS colour name.`);
113
+ }
114
+ if (options?.surfaces && !normalizeDualColor(options.surfaces)) {
115
+ throw new Error('The surfaces need a readable light and dark colour, e.g. { light: "#ffffff", dark: "#0b0b0f" }.');
116
+ }
117
+ const baseHex = formatHex(baseRgba);
118
+ const lab = rgbToOklab(baseRgba);
119
+ const lch = oklabToOklch(lab);
120
+ const startL = clamp(1.05 - lch.l, 0.12, 0.95);
121
+ const targetC = lch.c * 0.9;
122
+ const targetH = lch.h;
123
+ let derivedHex;
124
+ if (options?.surfaces) {
125
+ const surfaces = options.surfaces;
126
+ const fromSurfaceRgba = parseColor(surfaces[fromScheme]);
127
+ const targetScheme = fromScheme === "light" ? "dark" : "light";
128
+ const targetSurfaceRgba = parseColor(surfaces[targetScheme]);
129
+ const targetRatio = contrastRatio(baseRgba, fromSurfaceRgba);
130
+ const targetSurfaceL = oklabToOklch(rgbToOklab(targetSurfaceRgba)).l;
131
+ const preferHigherL = targetSurfaceL < 0.5;
132
+ let bestDiff = Infinity;
133
+ let bestL = startL;
134
+ for (let candL = 0.05; candL <= 0.98; candL += 5e-3) {
135
+ const candRgb = toSrgbGamut(
136
+ oklabToRgb(oklchToOklab({ l: candL, c: targetC, h: targetH, alpha: baseRgba.a }))
137
+ );
138
+ const ratio = contrastRatio(candRgb, targetSurfaceRgba);
139
+ const diff = Math.abs(ratio - targetRatio);
140
+ const isBetter = diff < bestDiff - 1e-4 || Math.abs(diff - bestDiff) <= 1e-4 && (preferHigherL ? candL > bestL : candL < bestL);
141
+ if (isBetter) {
142
+ bestDiff = diff;
143
+ bestL = candL;
144
+ }
145
+ }
146
+ const finalRgba = toSrgbGamut(
147
+ oklabToRgb(oklchToOklab({ l: bestL, c: targetC, h: targetH, alpha: baseRgba.a }))
148
+ );
149
+ derivedHex = formatHex(finalRgba);
150
+ } else {
151
+ const finalRgba = toSrgbGamut(
152
+ oklabToRgb(oklchToOklab({ l: startL, c: targetC, h: targetH, alpha: baseRgba.a }))
153
+ );
154
+ derivedHex = formatHex(finalRgba);
155
+ }
156
+ return fromScheme === "light" ? { light: baseHex, dark: derivedHex } : { light: derivedHex, dark: baseHex };
157
+ }
158
+ function checkDualColorContrast(foreground, background, options) {
159
+ const large = options?.large ?? false;
160
+ const requiredRatio = large ? 3 : 4.5;
161
+ const fg = normalizeDualColor(foreground);
162
+ const bg = normalizeDualColor(background);
163
+ if (!fg) throw new Error(`The foreground "${describeValue(foreground)}" is not a colour, light-dark() or { light, dark }.`);
164
+ if (!bg) throw new Error(`The background "${describeValue(background)}" is not a colour, light-dark() or { light, dark }.`);
165
+ const lightFgHex = fg.light;
166
+ const lightBgHex = bg.light;
167
+ const darkFgHex = fg.dark;
168
+ const darkBgHex = bg.dark;
169
+ const lightFg = parseColor(lightFgHex);
170
+ const lightBg = parseColor(lightBgHex);
171
+ const darkFg = parseColor(darkFgHex);
172
+ const darkBg = parseColor(darkBgHex);
173
+ const lightRatio = Math.round(contrastRatio(lightFg, lightBg) * 100) / 100;
174
+ const darkRatio = Math.round(contrastRatio(darkFg, darkBg) * 100) / 100;
175
+ const lightLevel = contrastLevel(lightRatio, { large });
176
+ const darkLevel = contrastLevel(darkRatio, { large });
177
+ const issues = [];
178
+ if (lightLevel === "fail") {
179
+ issues.push(
180
+ `In light mode, ${lightFgHex} on ${lightBgHex} has a contrast of ${lightRatio.toFixed(1)} (needs ${requiredRatio} for AA).`
181
+ );
182
+ }
183
+ if (darkLevel === "fail") {
184
+ issues.push(
185
+ `In dark mode, ${darkFgHex} on ${darkBgHex} has a contrast of ${darkRatio.toFixed(1)} (needs ${requiredRatio} for AA).`
186
+ );
187
+ }
188
+ return {
189
+ light: { ratio: lightRatio, level: lightLevel },
190
+ dark: { ratio: darkRatio, level: darkLevel },
191
+ issues
192
+ };
193
+ }
194
+ var CSS_VARIABLE_NAME = /^[A-Za-z_][A-Za-z0-9_-]*$/;
195
+ function describeValue(value) {
196
+ return typeof value === "string" ? value : JSON.stringify(value) ?? String(value);
197
+ }
198
+ function dualColorsToCss(colors, options) {
199
+ const selector = options?.selector ?? ":root";
200
+ const strategy = options?.strategy ?? "light-dark";
201
+ const darkSelector = options?.darkSelector ?? ".dark";
202
+ for (const [label, sel] of [["selector", selector], ["darkSelector", darkSelector]]) {
203
+ if (!sel.trim() || /[{};]/.test(sel)) {
204
+ throw new Error(`The ${label} "${sel}" is not a CSS selector (it can't be empty or contain "{", "}" or ";").`);
205
+ }
206
+ }
207
+ const normalized = {};
208
+ for (const [key, value] of Object.entries(colors)) {
209
+ if (!CSS_VARIABLE_NAME.test(key)) {
210
+ throw new Error(`"${key}" is not a CSS variable name; use letters, digits, "-" and "_" without the leading "--" (e.g. "brand-color").`);
211
+ }
212
+ const dual = normalizeDualColor(value);
213
+ if (!dual) throw new Error(`"${key}" has "${describeValue(value)}", which is not a colour, light-dark() or { light, dark }.`);
214
+ normalized[key] = dual;
215
+ }
216
+ const sortedKeys = Object.keys(normalized).sort();
217
+ switch (strategy) {
218
+ case "light-dark": {
219
+ const lines = [
220
+ `${selector} {`,
221
+ ...selector === ":root" ? [" color-scheme: light dark;"] : [],
222
+ ...sortedKeys.map((k) => {
223
+ return ` --${k}: ${formatDualColor(normalized[k])};`;
224
+ }),
225
+ "}"
226
+ ];
227
+ return lines.join("\n");
228
+ }
229
+ case "media": {
230
+ const lightLines = [
231
+ `${selector} {`,
232
+ ...sortedKeys.map((k) => ` --${k}: ${normalized[k].light};`),
233
+ "}"
234
+ ];
235
+ const darkLines = [
236
+ `@media (prefers-color-scheme: dark) {`,
237
+ ` ${selector} {`,
238
+ ...sortedKeys.map((k) => ` --${k}: ${normalized[k].dark};`),
239
+ ` }`,
240
+ `}`
241
+ ];
242
+ return `${lightLines.join("\n")}
243
+
244
+ ${darkLines.join("\n")}`;
245
+ }
246
+ case "class": {
247
+ const lightLines = [
248
+ `${selector} {`,
249
+ ...sortedKeys.map((k) => ` --${k}: ${normalized[k].light};`),
250
+ "}"
251
+ ];
252
+ const darkLines = [
253
+ `${darkSelector} {`,
254
+ ...sortedKeys.map((k) => ` --${k}: ${normalized[k].dark};`),
255
+ "}"
256
+ ];
257
+ return `${lightLines.join("\n")}
258
+
259
+ ${darkLines.join("\n")}`;
260
+ }
261
+ }
262
+ }
263
+
264
+ export {
265
+ DEFAULT_SCHEME_SURFACES,
266
+ isDualColor,
267
+ parseDualColor,
268
+ normalizeDualColor,
269
+ resolveColor,
270
+ formatDualColor,
271
+ isSameInBothSchemes,
272
+ setDualColorSide,
273
+ deriveDualColor,
274
+ checkDualColorContrast,
275
+ dualColorsToCss
276
+ };
@@ -7,7 +7,7 @@ import {
7
7
  listPresets,
8
8
  normalizeBrushSpec,
9
9
  resolveBrush
10
- } from "./chunk-JVRLGV3C.js";
10
+ } from "./chunk-SMTUQWGY.js";
11
11
  import {
12
12
  parseProvenance
13
13
  } from "./chunk-M6DNZNVY.js";