@pixerate/editor 0.246.0 → 0.248.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 (50) hide show
  1. package/dist/animation-editor/index.cjs +59 -59
  2. package/dist/animation-editor/index.js +3 -3
  3. package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-DTDPFBLC.cjs} +5 -5
  4. package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-QLCXROJK.js} +2 -2
  5. package/dist/canvas/index.cjs +8 -8
  6. package/dist/canvas/index.js +1 -1
  7. package/dist/{chunk-DQWPMGH2.js → chunk-5GLYUSNT.js} +1 -1
  8. package/dist/{chunk-Q2UYUWAZ.cjs → chunk-6G6ZDDDB.cjs} +390 -27
  9. package/dist/chunk-7T7JWTVE.cjs +192 -0
  10. package/dist/{chunk-UVPD55UZ.cjs → chunk-IBDU6EGZ.cjs} +35 -35
  11. package/dist/{chunk-FK5LTDOO.cjs → chunk-L6REDLNB.cjs} +2 -2
  12. package/dist/{chunk-LDPLEZ5T.js → chunk-NZ3O3A5C.js} +1 -1
  13. package/dist/{chunk-N6WUB3Y5.js → chunk-Q2HA52V4.js} +1 -1
  14. package/dist/chunk-SC2RZ5EF.js +192 -0
  15. package/dist/{chunk-5MFDD7SP.cjs → chunk-TPWB4Y6L.cjs} +1 -1
  16. package/dist/{chunk-VDAWA546.js → chunk-VNBUDVD4.js} +388 -25
  17. package/dist/{chunk-XTWXBQD4.cjs → chunk-WVS5KQDH.cjs} +442 -87
  18. package/dist/{chunk-A23PSOBB.js → chunk-XNRBMYNB.js} +1 -1
  19. package/dist/{chunk-CEPKXLBS.cjs → chunk-XWTRATIM.cjs} +23 -23
  20. package/dist/{chunk-4PMCMWQS.js → chunk-ZFSLEOSQ.js} +357 -2
  21. package/dist/image-editor/effect-tools.d.cts +37 -4
  22. package/dist/image-editor/effect-tools.d.ts +37 -4
  23. package/dist/image-editor/index.cjs +1059 -1552
  24. package/dist/image-editor/index.d.cts +1 -1
  25. package/dist/image-editor/index.d.ts +1 -1
  26. package/dist/image-editor/index.js +275 -768
  27. package/dist/paint-editor/controller.d.cts +34 -1
  28. package/dist/paint-editor/controller.d.ts +34 -1
  29. package/dist/paint-editor/index.cjs +426 -257
  30. package/dist/paint-editor/index.js +184 -15
  31. package/dist/paint-editor/procedural.d.cts +82 -5
  32. package/dist/paint-editor/procedural.d.ts +82 -5
  33. package/dist/paint-editor/tools.d.cts +1 -1
  34. package/dist/paint-editor/tools.d.ts +1 -1
  35. package/dist/paint-editor/ui.d.cts +15 -2
  36. package/dist/paint-editor/ui.d.ts +15 -2
  37. package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.cts} +32 -5
  38. package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.ts} +32 -5
  39. package/dist/raster/index.cjs +13 -1
  40. package/dist/raster/index.d.cts +1 -0
  41. package/dist/raster/index.d.ts +1 -0
  42. package/dist/raster/index.js +12 -0
  43. package/dist/vector/index.cjs +962 -962
  44. package/dist/vector/index.js +4 -4
  45. package/package.json +1 -1
  46. package/skills/pixerate-paint-editor/SKILL.md +18 -27
  47. package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
  48. package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
  49. package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
  50. package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
@@ -8,7 +8,7 @@ import {
8
8
  parseOpenTypeFont,
9
9
  removeAnchorsKeepingShape,
10
10
  traceField
11
- } from "../chunk-DQWPMGH2.js";
11
+ } from "../chunk-5GLYUSNT.js";
12
12
  import {
13
13
  ColorGmm,
14
14
  GAMMA,
@@ -153,6 +153,8 @@ import {
153
153
  copySmartObject,
154
154
  cornersFromMatrix,
155
155
  createAdjustmentLayer,
156
+ createImageEffectTools,
157
+ createLayerEffectTools,
156
158
  createShapeLayer,
157
159
  createTypeLayer,
158
160
  curveLutFromLevels,
@@ -167,6 +169,7 @@ import {
167
169
  defaultShapeName,
168
170
  depthMaskAlpha,
169
171
  depthRasterMask,
172
+ describeLayerEffects,
170
173
  describeTransform,
171
174
  deserializeEffects,
172
175
  deserializeLayer,
@@ -410,7 +413,7 @@ import {
410
413
  writePsd,
411
414
  xyToTempTint,
412
415
  xyToUv
413
- } from "../chunk-4PMCMWQS.js";
416
+ } from "../chunk-ZFSLEOSQ.js";
414
417
  import {
415
418
  parseCssColor
416
419
  } from "../chunk-3CI7FRMK.js";
@@ -465,6 +468,13 @@ import {
465
468
  import {
466
469
  createCaptureTool
467
470
  } from "../chunk-5ED73EC6.js";
471
+ import {
472
+ LAYER_EFFECT_MENU,
473
+ effectControlChange,
474
+ layerEffectControls,
475
+ layerEffectsBadge,
476
+ layerEffectsPanel
477
+ } from "../chunk-SC2RZ5EF.js";
468
478
  import {
469
479
  DEFAULT_GLOBAL_LIGHT,
470
480
  INTERPOLATIONS,
@@ -733,8 +743,8 @@ import {
733
743
  warpMeshParamAt,
734
744
  warpMeshRows,
735
745
  warpPresetMesh
736
- } from "../chunk-N6WUB3Y5.js";
737
- import "../chunk-VDAWA546.js";
746
+ } from "../chunk-Q2HA52V4.js";
747
+ import "../chunk-VNBUDVD4.js";
738
748
  import "../chunk-M6DNZNVY.js";
739
749
  import {
740
750
  bezierPathToSvg,
@@ -1686,13 +1696,13 @@ var ImageEditorRenderer = class {
1686
1696
  ctx.save();
1687
1697
  try {
1688
1698
  applyImageProjectionToContext(ctx, projection);
1689
- const px2 = u / (projection.scale || 1);
1699
+ const px = u / (projection.scale || 1);
1690
1700
  ctx.beginPath();
1691
- ctx.arc(b.x, b.y, Math.max(px2, b.diameter / 2), 0, Math.PI * 2);
1692
- ctx.lineWidth = 2 * px2;
1701
+ ctx.arc(b.x, b.y, Math.max(px, b.diameter / 2), 0, Math.PI * 2);
1702
+ ctx.lineWidth = 2 * px;
1693
1703
  ctx.strokeStyle = "rgba(0,0,0,0.6)";
1694
1704
  ctx.stroke();
1695
- ctx.lineWidth = px2;
1705
+ ctx.lineWidth = px;
1696
1706
  ctx.strokeStyle = "#ffffff";
1697
1707
  ctx.stroke();
1698
1708
  } catch {
@@ -2239,32 +2249,32 @@ var ImageEditorRenderer = class {
2239
2249
  this.outlineCache.set(selection, paths);
2240
2250
  }
2241
2251
  if (!paths.length) return;
2242
- const px2 = 1 / (scale || 1);
2252
+ const px = 1 / (scale || 1);
2243
2253
  ctx.beginPath();
2244
2254
  for (const p of paths) {
2245
2255
  ctx.moveTo(p[0], p[1]);
2246
2256
  for (let i = 2; i < p.length; i += 2) ctx.lineTo(p[i], p[i + 1]);
2247
2257
  }
2248
- ctx.lineWidth = px2;
2258
+ ctx.lineWidth = px;
2249
2259
  ctx.strokeStyle = "#ffffff";
2250
2260
  ctx.stroke();
2251
2261
  if (typeof ctx.setLineDash === "function") {
2252
- ctx.setLineDash([4 * px2, 4 * px2]);
2253
- ctx.lineDashOffset = -offset * px2;
2262
+ ctx.setLineDash([4 * px, 4 * px]);
2263
+ ctx.lineDashOffset = -offset * px;
2254
2264
  }
2255
2265
  ctx.strokeStyle = "#000000";
2256
2266
  ctx.stroke();
2257
2267
  if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
2258
2268
  }
2259
2269
  drawDraftPath(ctx, points, scale) {
2260
- const px2 = 1 / (scale || 1);
2270
+ const px = 1 / (scale || 1);
2261
2271
  ctx.beginPath();
2262
2272
  points.forEach((p, i) => i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y));
2263
2273
  ctx.closePath();
2264
- ctx.lineWidth = px2;
2274
+ ctx.lineWidth = px;
2265
2275
  ctx.strokeStyle = "#ffffff";
2266
2276
  ctx.stroke();
2267
- if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px2, 4 * px2]);
2277
+ if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px, 4 * px]);
2268
2278
  ctx.strokeStyle = "#000000";
2269
2279
  ctx.stroke();
2270
2280
  if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
@@ -2929,9 +2939,9 @@ function inspectMaskEdge(mask, image, options = {}) {
2929
2939
  turnExcess += Math.max(0, total - closure);
2930
2940
  outline += L;
2931
2941
  for (let i = 0; i < n; i++) {
2932
- const [px2, py] = pts[i];
2933
- if (px2 < 0 || py < 0 || px2 >= W || py >= H) continue;
2934
- const blk = block(Math.floor(px2), Math.floor(py));
2942
+ const [px, py] = pts[i];
2943
+ if (px < 0 || py < 0 || px >= W || py >= H) continue;
2944
+ const blk = block(Math.floor(px), Math.floor(py));
2935
2945
  blk.turn += Math.abs(turns[i]) - closure / n;
2936
2946
  blk.len += 2;
2937
2947
  }
@@ -4118,10 +4128,10 @@ function liveWire(map, from, to, band) {
4118
4128
  const uy = (by - ay) / len;
4119
4129
  for (let y = 0; y < h; y++) {
4120
4130
  for (let x = 0; x < w; x++) {
4121
- const px2 = rx0 + x - ax;
4131
+ const px = rx0 + x - ax;
4122
4132
  const py = ry0 + y - ay;
4123
- const t = Math.min(len, Math.max(0, px2 * ux + py * uy));
4124
- if (Math.hypot(px2 - t * ux, py - t * uy) > half) continue;
4133
+ const t = Math.min(len, Math.max(0, px * ux + py * uy));
4134
+ if (Math.hypot(px - t * ux, py - t * uy) > half) continue;
4125
4135
  const i = y * w + x;
4126
4136
  inside[i] = 1;
4127
4137
  const f = map.features(rx0 + x, ry0 + y);
@@ -5015,43 +5025,43 @@ function liftPixels(surface, sel, o) {
5015
5025
  const area = { x: sb.x - o.x, y: sb.y - o.y, width: sb.width, height: sb.height };
5016
5026
  const depth = surfaceDepth(surface);
5017
5027
  if (depth !== 8) {
5018
- const px3 = readDeepRegion(surface, area, depth);
5019
- const kept2 = px3.slice();
5028
+ const px2 = readDeepRegion(surface, area, depth);
5029
+ const kept2 = px2.slice();
5020
5030
  const r16 = depth === 16;
5021
5031
  for (let y = 0; y < area.height; y++) {
5022
5032
  for (let x = 0; x < area.width; x++) {
5023
5033
  const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
5024
5034
  const i = (y * area.width + x) * 4;
5025
5035
  if (k <= 0) {
5026
- px3[i] = px3[i + 1] = px3[i + 2] = px3[i + 3] = 0;
5036
+ px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
5027
5037
  continue;
5028
5038
  }
5029
- px3[i + 3] = r16 ? Math.round(px3[i + 3] * k) : px3[i + 3] * k;
5030
- if (!px3[i + 3]) px3[i] = px3[i + 1] = px3[i + 2] = 0;
5039
+ px2[i + 3] = r16 ? Math.round(px2[i + 3] * k) : px2[i + 3] * k;
5040
+ if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
5031
5041
  kept2[i + 3] = r16 ? Math.round(kept2[i + 3] * (1 - k)) : kept2[i + 3] * (1 - k);
5032
5042
  if (!kept2[i + 3]) kept2[i] = kept2[i + 1] = kept2[i + 2] = 0;
5033
5043
  }
5034
5044
  }
5035
- const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px3);
5045
+ const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px2);
5036
5046
  return { lifted, rest: writeDeepRegion(surface, area, kept2) };
5037
5047
  }
5038
- const px2 = readRegion(surface, area);
5039
- const kept = new Uint8ClampedArray(px2);
5048
+ const px = readRegion(surface, area);
5049
+ const kept = new Uint8ClampedArray(px);
5040
5050
  for (let y = 0; y < area.height; y++) {
5041
5051
  for (let x = 0; x < area.width; x++) {
5042
5052
  const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
5043
5053
  const i = (y * area.width + x) * 4;
5044
5054
  if (k <= 0) {
5045
- px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
5055
+ px[i] = px[i + 1] = px[i + 2] = px[i + 3] = 0;
5046
5056
  continue;
5047
5057
  }
5048
- px2[i + 3] = px2[i + 3] * k;
5049
- if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
5058
+ px[i + 3] = px[i + 3] * k;
5059
+ if (!px[i + 3]) px[i] = px[i + 1] = px[i + 2] = 0;
5050
5060
  kept[i + 3] = kept[i + 3] * (1 - k);
5051
5061
  if (!kept[i + 3]) kept[i] = kept[i + 1] = kept[i + 2] = 0;
5052
5062
  }
5053
5063
  }
5054
- return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px2 }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
5064
+ return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
5055
5065
  }
5056
5066
  function liftMask(mask, sel, o) {
5057
5067
  const sb = sel.bounds;
@@ -5642,14 +5652,14 @@ function displayTransform(doc, proof) {
5642
5652
  const g = gamut;
5643
5653
  return (rgba) => {
5644
5654
  if (g) {
5645
- const px2 = [0, 0, 0];
5655
+ const px = [0, 0, 0];
5646
5656
  const flags = new Uint8Array(rgba.length >> 2);
5647
5657
  for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
5648
5658
  if (rgba[i + 3] === 0) continue;
5649
- px2[0] = rgba[i] / 255;
5650
- px2[1] = rgba[i + 1] / 255;
5651
- px2[2] = rgba[i + 2] / 255;
5652
- if (g.outOfGamut(px2)) flags[p] = 1;
5659
+ px[0] = rgba[i] / 255;
5660
+ px[1] = rgba[i + 1] / 255;
5661
+ px[2] = rgba[i + 2] / 255;
5662
+ if (g.outOfGamut(px)) flags[p] = 1;
5653
5663
  }
5654
5664
  tr.convert8(rgba, 4, rgba, 4);
5655
5665
  for (let i = 0, p = 0; i < rgba.length; i += 4, p++) if (flags[p]) rgba[i] = rgba[i + 1] = rgba[i + 2] = 128;
@@ -6453,12 +6463,12 @@ var ImageEditorController = class {
6453
6463
  } else {
6454
6464
  const sb = sel.bounds;
6455
6465
  const src = { x: sb.x - layer.offset.x, y: sb.y - layer.offset.y, width: sb.width, height: sb.height };
6456
- const px2 = readRegion(surface, src);
6466
+ const px = readRegion(surface, src);
6457
6467
  const data = sel.data;
6458
6468
  for (let y = 0; y < sb.height; y++) {
6459
- for (let x = 0; x < sb.width; x++) px2[(y * sb.width + x) * 4 + 3] = Math.round(px2[(y * sb.width + x) * 4 + 3] * (data[(sb.y + y) * width + sb.x + x] / 255));
6469
+ for (let x = 0; x < sb.width; x++) px[(y * sb.width + x) * 4 + 3] = Math.round(px[(y * sb.width + x) * 4 + 3] * (data[(sb.y + y) * width + sb.x + x] / 255));
6460
6470
  }
6461
- copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px2 }, 4, src.x, src.y) };
6471
+ copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y) };
6462
6472
  delete copy.mask;
6463
6473
  }
6464
6474
  delete copy.source;
@@ -7109,9 +7119,9 @@ var ImageEditorController = class {
7109
7119
  const bounds = this.getLayerBounds(layer.id);
7110
7120
  if (bounds && point2.x >= bounds.x && point2.x <= bounds.x + bounds.width && point2.y >= bounds.y && point2.y <= bounds.y + bounds.height) {
7111
7121
  const surface = this.surfaceOf(layer);
7112
- const px2 = Math.floor(point2.x - layer.offset.x);
7122
+ const px = Math.floor(point2.x - layer.offset.x);
7113
7123
  const py = Math.floor(point2.y - layer.offset.y);
7114
- const pixel = readPixel(surface, px2, py);
7124
+ const pixel = readPixel(surface, px, py);
7115
7125
  if (pixel.length >= 4 && pixel[3] >= alphaThreshold) return layer.id;
7116
7126
  }
7117
7127
  return null;
@@ -7123,9 +7133,9 @@ var ImageEditorController = class {
7123
7133
  return null;
7124
7134
  }
7125
7135
  const surface = this.surfaceOf(layer);
7126
- const px2 = Math.floor(point2.x - layer.offset.x);
7136
+ const px = Math.floor(point2.x - layer.offset.x);
7127
7137
  const py = Math.floor(point2.y - layer.offset.y);
7128
- const pixel = readPixel(surface, px2, py);
7138
+ const pixel = readPixel(surface, px, py);
7129
7139
  if (pixel.length >= 4 && pixel[3] >= alphaThreshold) {
7130
7140
  return layer.id;
7131
7141
  }
@@ -7276,17 +7286,17 @@ var ImageEditorController = class {
7276
7286
  */
7277
7287
  sourceSurface() {
7278
7288
  const { width, height } = this.naturalSize;
7279
- const fromPixels = (px3) => {
7280
- let s = this.sourceSurfaces.get(px3);
7289
+ const fromPixels = (px2) => {
7290
+ let s = this.sourceSurfaces.get(px2);
7281
7291
  if (!s) {
7282
- s = surfaceFromPixels(px3, 4);
7283
- this.sourceSurfaces.set(px3, s);
7292
+ s = surfaceFromPixels(px2, 4);
7293
+ this.sourceSurfaces.set(px2, s);
7284
7294
  }
7285
7295
  return s;
7286
7296
  };
7287
- const px2 = this.samplePixels;
7288
- const fits = Boolean(px2 && px2.width === width && px2.height === height);
7289
- if (this.samplePixelsOverride && fits) return fromPixels(px2);
7297
+ const px = this.samplePixels;
7298
+ const fits = Boolean(px && px.width === width && px.height === height);
7299
+ if (this.samplePixelsOverride && fits) return fromPixels(px);
7290
7300
  const el = this.imageElement;
7291
7301
  if (el) {
7292
7302
  const cached = this.sourceSurfaces.get(el);
@@ -7300,7 +7310,7 @@ var ImageEditorController = class {
7300
7310
  return s;
7301
7311
  }
7302
7312
  }
7303
- return fits ? fromPixels(px2) : null;
7313
+ return fits ? fromPixels(px) : null;
7304
7314
  }
7305
7315
  opaqueCache = /* @__PURE__ */ new WeakMap();
7306
7316
  /** Whether every source pixel is opaque (some legacy renders depend on it). */
@@ -7362,11 +7372,11 @@ var ImageEditorController = class {
7362
7372
  const { width, height } = this.naturalSize;
7363
7373
  let surface = emptySurface(4);
7364
7374
  if (init.pixels) {
7365
- const px2 = init.pixels;
7366
- if (!(px2.width > 0 && px2.height > 0) || px2.data.length < px2.width * px2.height * 4) {
7375
+ const px = init.pixels;
7376
+ if (!(px.width > 0 && px.height > 0) || px.data.length < px.width * px.height * 4) {
7367
7377
  throw new LayerOperationError("pixels must be RGBA with width \xD7 height \xD7 4 bytes.");
7368
7378
  }
7369
- surface = surfaceFromPixels(px2, 4);
7379
+ surface = surfaceFromPixels(px, 4);
7370
7380
  } else if (init.color !== void 0) {
7371
7381
  const c = parseColor(init.color);
7372
7382
  surface = solidSurface(4, { x: 0, y: 0, width, height }, packRgba(c[0], c[1], c[2], c[3]));
@@ -7470,9 +7480,9 @@ var ImageEditorController = class {
7470
7480
  getEdgeColor(id) {
7471
7481
  const layer = this.requireEdgeLayer(id);
7472
7482
  const e = layer.edge ?? {};
7473
- const pct2 = (v) => Math.round((v ?? 0) * 1e3) / 10;
7483
+ const pct = (v) => Math.round((v ?? 0) * 1e3) / 10;
7474
7484
  const hex = (c) => "#" + c.map((v) => v.toString(16).padStart(2, "0")).join("");
7475
- return { layerId: layer.id, decontaminate: pct2(e.decontaminate), despill: pct2(e.despill), ambient: pct2(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
7485
+ return { layerId: layer.id, decontaminate: pct(e.decontaminate), despill: pct(e.despill), ambient: pct(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
7476
7486
  }
7477
7487
  requireEdgeLayer(id) {
7478
7488
  const layer = this.getLayer(id);
@@ -7527,9 +7537,9 @@ var ImageEditorController = class {
7527
7537
  throw new LayerOperationError(`"${name}" has no mask with a soft edge: decontamination and despill work in the partly hidden band of a layer mask. Add one with add_layer_mask from a refined selection (refine_selection), or feather the mask (set_layer_mask_properties feather).`);
7528
7538
  }
7529
7539
  if (turningOn("ambient") && !this.maskHasSoftBand(layer) && layer.type === "pixel") {
7530
- const px2 = this.getLayerPixels(layer.id);
7540
+ const px = this.getLayerPixels(layer.id);
7531
7541
  let soft = false;
7532
- if (px2) for (let i = 3; i < px2.data.length && !soft; i += 4) soft = px2.data[i] > 5 && px2.data[i] < 250;
7542
+ if (px) for (let i = 3; i < px.data.length && !soft; i += 4) soft = px.data[i] > 5 && px.data[i] < 250;
7533
7543
  if (!soft) throw new LayerOperationError(`"${name}" has no soft edge (no soft-edged mask and no partly transparent pixels) for the edge cast to work on.`);
7534
7544
  }
7535
7545
  const edge = next.decontaminate || next.despill || next.ambient || next.ambientColor ? next : void 0;
@@ -8155,14 +8165,14 @@ var ImageEditorController = class {
8155
8165
  const surface = this.surfaceOf(layer);
8156
8166
  const sb = sel.bounds;
8157
8167
  const src = { x: sb.x - layer.offset.x, y: sb.y - layer.offset.y, width: sb.width, height: sb.height };
8158
- const px2 = readRegion(surface, src);
8159
- const kept = options.cut ? new Uint8ClampedArray(px2) : null;
8168
+ const px = readRegion(surface, src);
8169
+ const kept = options.cut ? new Uint8ClampedArray(px) : null;
8160
8170
  for (let y = 0; y < sb.height; y++) {
8161
8171
  for (let x = 0; x < sb.width; x++) {
8162
8172
  const c = sel.data[(sb.y + y) * sel.width + sb.x + x];
8163
8173
  const i = (y * sb.width + x) * 4 + 3;
8164
8174
  if (kept) kept[i] = Math.round(kept[i] * (1 - c / 255));
8165
- px2[i] = Math.round(px2[i] * (c / 255));
8175
+ px[i] = Math.round(px[i] * (c / 255));
8166
8176
  }
8167
8177
  }
8168
8178
  const copy = {
@@ -8172,7 +8182,7 @@ var ImageEditorController = class {
8172
8182
  visible: true,
8173
8183
  opacity: 1,
8174
8184
  blend: "normal",
8175
- surface: surfaceFromPixels({ width: src.width, height: src.height, data: px2 }, 4, src.x, src.y),
8185
+ surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y),
8176
8186
  offset: { ...layer.offset }
8177
8187
  };
8178
8188
  let next = insertLayer(this.state.layers, copy, loc.parent?.id ?? null, loc.index + 1);
@@ -8609,8 +8619,8 @@ var ImageEditorController = class {
8609
8619
  for (const [cid, c] of pending) {
8610
8620
  try {
8611
8621
  const url = `data:${BROWSER_IMAGE_TYPES[c.file.type]};base64,${bytesToBase64(c.file.bytes)}`;
8612
- const px2 = await this.decodeImage(url);
8613
- const decoded = { ...c, kind: "raster", raster: rasterContents(px2, c.name, cid).raster, width: px2.width, height: px2.height };
8622
+ const px = await this.decodeImage(url);
8623
+ const decoded = { ...c, kind: "raster", raster: rasterContents(px, c.name, cid).raster, width: px.width, height: px.height };
8614
8624
  const swap = (layers) => {
8615
8625
  let out = layers;
8616
8626
  for (const l of flattenLayers(layers)) if (l.type === "smart" && l.contents.id === cid) out = mapLayer(out, l.id, (x) => ({ ...x, contents: decoded }));
@@ -8706,8 +8716,8 @@ var ImageEditorController = class {
8706
8716
  const only = edited.layers.length === 1 ? edited.layers[0] : null;
8707
8717
  const plain3 = only?.type === "pixel" && only.visible && only.opacity === 1 && only.blend === "normal" && !only.mask && !only.effects && !only.filters?.length && !only.clipped && (only.fillOpacity ?? 1) === 1 && only.source !== "document";
8708
8718
  if (old?.kind === "raster" && plain3) {
8709
- const px2 = readRegion(only.surface, { x: -only.offset.x, y: -only.offset.y, width, height });
8710
- next = rasterContents({ width, height, data: px2 }, old.name, old.id);
8719
+ const px = readRegion(only.surface, { x: -only.offset.x, y: -only.offset.y, width, height });
8720
+ next = rasterContents({ width, height, data: px }, old.name, old.id);
8711
8721
  } else {
8712
8722
  const doc = { layers: edited.layers, globalLight: edited.globalLight, patterns: edited.patterns };
8713
8723
  next = documentContents(doc, width, height, old?.kind === "document" ? old.name : `${(old?.name ?? "Contents").replace(/\.\w+$/, "")}.psb`, top.contentsId);
@@ -11499,9 +11509,9 @@ var ImageEditorController = class {
11499
11509
  return;
11500
11510
  }
11501
11511
  const { width, height } = this.naturalSize;
11502
- let px2 = await this.decodeImage(newDataUrl);
11503
- if (px2.width !== width || px2.height !== height) px2 = resizePixels(px2, width, height);
11504
- const data = new Uint8ClampedArray(px2.data);
11512
+ let px = await this.decodeImage(newDataUrl);
11513
+ if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
11514
+ const data = new Uint8ClampedArray(px.data);
11505
11515
  const sel = this.state.selection?.bounds ? this.state.selection : null;
11506
11516
  if (sel) for (let p = 0, i = 3; p < width * height; p++, i += 4) data[i] = Math.round(data[i] * sel.data[p] / 255);
11507
11517
  return this.addPixelLayer({ name: "Inpaint", pixels: { width, height, data } });
@@ -11522,10 +11532,10 @@ var ImageEditorController = class {
11522
11532
  if (!target) throw new LayerOperationError("There is no pixel layer to mask.");
11523
11533
  requireUnlocked(target, "all", "mask it");
11524
11534
  const { width, height } = this.naturalSize;
11525
- let px2 = await this.decodeImage(newDataUrl);
11526
- if (px2.width !== width || px2.height !== height) px2 = resizePixels(px2, width, height);
11535
+ let px = await this.decodeImage(newDataUrl);
11536
+ if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
11527
11537
  const alpha = new Uint8ClampedArray(width * height);
11528
- for (let p = 0; p < alpha.length; p++) alpha[p] = px2.data[p * 4 + 3];
11538
+ for (let p = 0; p < alpha.length; p++) alpha[p] = px.data[p * 4 + 3];
11529
11539
  let surface = surfaceFromPixels({ width, height, data: alpha }, 1, 0, 0, 0);
11530
11540
  if (target.offset.x || target.offset.y) surface = translateSurface(surface, -target.offset.x, -target.offset.y);
11531
11541
  this.commitLayers(setLayerMask(this.state.layers, target.id, { surface, defaultValue: 0 }));
@@ -12098,14 +12108,14 @@ var ImageEditorController = class {
12098
12108
  const converted = [];
12099
12109
  const unconverted = [];
12100
12110
  const memo = /* @__PURE__ */ new Map();
12101
- const px2 = new Float32Array(4);
12111
+ const px = new Float32Array(4);
12102
12112
  const hex = (h) => {
12103
12113
  let out = memo.get(h.toLowerCase());
12104
12114
  if (out === void 0) {
12105
12115
  const n = parseInt(h.slice(1), 16);
12106
- t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px2);
12116
+ t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px);
12107
12117
  const c = (v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0");
12108
- out = `#${c(px2[0])}${c(px2[1])}${c(px2[2])}`;
12118
+ out = `#${c(px[0])}${c(px[1])}${c(px[2])}`;
12109
12119
  memo.set(h.toLowerCase(), out);
12110
12120
  }
12111
12121
  return out;
@@ -12914,24 +12924,24 @@ function pixelsOnly(layers) {
12914
12924
  }
12915
12925
  return out;
12916
12926
  }
12917
- function resizePixels(px2, width, height) {
12918
- const src = px2.data;
12927
+ function resizePixels(px, width, height) {
12928
+ const src = px.data;
12919
12929
  const out = new Uint8ClampedArray(width * height * 4);
12920
- const kx = px2.width / width;
12921
- const ky = px2.height / height;
12930
+ const kx = px.width / width;
12931
+ const ky = px.height / height;
12922
12932
  for (let y = 0; y < height; y++) {
12923
- const fy = Math.min(px2.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
12933
+ const fy = Math.min(px.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
12924
12934
  const y0 = Math.floor(fy);
12925
- const y1 = Math.min(px2.height - 1, y0 + 1);
12935
+ const y1 = Math.min(px.height - 1, y0 + 1);
12926
12936
  const ty = fy - y0;
12927
12937
  for (let x = 0; x < width; x++) {
12928
- const fx = Math.min(px2.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
12938
+ const fx = Math.min(px.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
12929
12939
  const x0 = Math.floor(fx);
12930
- const x1 = Math.min(px2.width - 1, x0 + 1);
12940
+ const x1 = Math.min(px.width - 1, x0 + 1);
12931
12941
  const tx = fx - x0;
12932
12942
  for (let c = 0; c < 4; c++) {
12933
- const a = src[(y0 * px2.width + x0) * 4 + c] * (1 - tx) + src[(y0 * px2.width + x1) * 4 + c] * tx;
12934
- const b = src[(y1 * px2.width + x0) * 4 + c] * (1 - tx) + src[(y1 * px2.width + x1) * 4 + c] * tx;
12943
+ const a = src[(y0 * px.width + x0) * 4 + c] * (1 - tx) + src[(y0 * px.width + x1) * 4 + c] * tx;
12944
+ const b = src[(y1 * px.width + x0) * 4 + c] * (1 - tx) + src[(y1 * px.width + x1) * 4 + c] * tx;
12935
12945
  out[(y * width + x) * 4 + c] = a * (1 - ty) + b * ty;
12936
12946
  }
12937
12947
  }
@@ -13803,8 +13813,8 @@ var REFINE_OUTPUTS = [
13803
13813
  ];
13804
13814
  function describeSelection(mask) {
13805
13815
  if (!mask || !mask.bounds) return "No selection";
13806
- const pct2 = selectionArea(mask) / (mask.width * mask.height) * 100;
13807
- const shown = pct2 >= 10 ? Math.round(pct2) : Math.round(pct2 * 10) / 10;
13816
+ const pct = selectionArea(mask) / (mask.width * mask.height) * 100;
13817
+ const shown = pct >= 10 ? Math.round(pct) : Math.round(pct * 10) / 10;
13808
13818
  return `${mask.bounds.width} \xD7 ${mask.bounds.height} px selected (${shown}% of the image)`;
13809
13819
  }
13810
13820
 
@@ -15341,14 +15351,14 @@ function rebin(bins, count) {
15341
15351
  return out;
15342
15352
  }
15343
15353
  function histogramSummary(h, bins) {
15344
- const pct2 = (n) => h.samples ? round(n / h.samples * 100) : 0;
15354
+ const pct = (n) => h.samples ? round(n / h.samples * 100) : 0;
15345
15355
  const channels = { red: h.red, green: h.green, blue: h.blue, luminance: h.luminance };
15346
15356
  return {
15347
15357
  samples: h.samples,
15348
15358
  transparent: h.transparent,
15349
15359
  clipping: {
15350
- shadowsPercent: { red: pct2(h.shadows[0]), green: pct2(h.shadows[1]), blue: pct2(h.shadows[2]) },
15351
- highlightsPercent: { red: pct2(h.highlights[0]), green: pct2(h.highlights[1]), blue: pct2(h.highlights[2]) }
15360
+ shadowsPercent: { red: pct(h.shadows[0]), green: pct(h.shadows[1]), blue: pct(h.shadows[2]) },
15361
+ highlightsPercent: { red: pct(h.highlights[0]), green: pct(h.highlights[1]), blue: pct(h.highlights[2]) }
15352
15362
  },
15353
15363
  stats: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, binStats(v, h.samples)])),
15354
15364
  ...bins ? { bins: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, rebin(v, bins)])) } : {}
@@ -16249,337 +16259,6 @@ function createImageLayerTools(controller) {
16249
16259
  ];
16250
16260
  }
16251
16261
 
16252
- // src/image-editor/effect-tools.ts
16253
- var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
16254
- var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
16255
- var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
16256
- var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
16257
- var LAYER_ID3 = { type: "string", description: "Layer id from list_layers (a pixel, shape, smart object, annotation or group layer)." };
16258
- var EFFECT_ID = { type: "string", description: "Effect id from list_layer_effects or add_layer_effect." };
16259
- var BLEND_IDS = BLEND_MODES.map((m) => m.id).filter((id) => id !== "pigment");
16260
- var DEFS = {
16261
- color: { type: "string", pattern: "^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$", description: "Colour as #rrggbb." },
16262
- contour: {
16263
- type: "object",
16264
- description: "A transfer curve over the effect coverage: points { input, output } from 0 to 1 (at least 2), sorted by input. Linear is [{0,0},{1,1}].",
16265
- properties: {
16266
- name: { type: "string", description: 'Display name (e.g. "Cone", "Gaussian").' },
16267
- points: {
16268
- type: "array",
16269
- minItems: 2,
16270
- description: "Curve points.",
16271
- items: {
16272
- type: "object",
16273
- properties: {
16274
- input: { type: "number", minimum: 0, maximum: 1, description: "Coverage in (0..1)." },
16275
- output: { type: "number", minimum: 0, maximum: 1, description: "Coverage out (0..1)." },
16276
- corner: { type: "boolean", description: "Sharp corner instead of a smooth point (default false)." }
16277
- },
16278
- required: ["input", "output"],
16279
- additionalProperties: false
16280
- }
16281
- }
16282
- },
16283
- required: ["name", "points"],
16284
- additionalProperties: false
16285
- },
16286
- gradient: {
16287
- type: "object",
16288
- description: "A gradient: colour stops, optional opacity stops and its layout.",
16289
- properties: {
16290
- stops: {
16291
- type: "array",
16292
- minItems: 1,
16293
- description: "Colour stops { position 0..1, color #rrggbb }.",
16294
- items: {
16295
- type: "object",
16296
- properties: { position: { type: "number", minimum: 0, maximum: 1, description: "0..1 along the gradient." }, color: { $ref: "#/$defs/color" } },
16297
- required: ["position", "color"],
16298
- additionalProperties: false
16299
- }
16300
- },
16301
- opacityStops: {
16302
- type: "array",
16303
- description: "Opacity stops { position 0..1, opacity 0..1 } (default opaque).",
16304
- items: {
16305
- type: "object",
16306
- properties: {
16307
- position: { type: "number", minimum: 0, maximum: 1, description: "0..1 along the gradient." },
16308
- opacity: { type: "number", minimum: 0, maximum: 1, description: "0..1." }
16309
- },
16310
- required: ["position", "opacity"],
16311
- additionalProperties: false
16312
- }
16313
- },
16314
- style: { type: "string", enum: ["linear", "radial", "angle", "reflected", "diamond"], description: "Geometry." },
16315
- angle: { type: "number", minimum: -360, maximum: 360, description: "Degrees, 90 = bottom to top." },
16316
- scale: { type: "number", minimum: 0.1, maximum: 1.5, description: "1 = 100 %." },
16317
- reverse: { type: "boolean", description: "Swap the ends." },
16318
- align: { type: "boolean", description: "Lay out over the layer bounds (true) or the canvas." },
16319
- offset: {
16320
- type: "object",
16321
- description: "Centre offset as fractions of the bounds.",
16322
- properties: { x: { type: "number", minimum: -1, maximum: 1, description: "Fraction of the width." }, y: { type: "number", minimum: -1, maximum: 1, description: "Fraction of the height." } },
16323
- required: ["x", "y"],
16324
- additionalProperties: false
16325
- }
16326
- },
16327
- required: ["stops", "style", "angle", "scale", "reverse", "align", "offset"],
16328
- additionalProperties: false
16329
- },
16330
- phase: {
16331
- type: "object",
16332
- description: "Pattern origin offset in px.",
16333
- properties: { x: { type: "number", description: "px." }, y: { type: "number", description: "px." } },
16334
- required: ["x", "y"],
16335
- additionalProperties: false
16336
- },
16337
- fill: {
16338
- description: "What a stroke or glow paints with. Glows take color or gradient only.",
16339
- anyOf: [
16340
- {
16341
- type: "object",
16342
- properties: { type: { const: "color", description: "Solid colour." }, color: { $ref: "#/$defs/color" } },
16343
- required: ["type", "color"],
16344
- additionalProperties: false
16345
- },
16346
- {
16347
- type: "object",
16348
- properties: { type: { const: "gradient", description: "Gradient." }, gradient: { $ref: "#/$defs/gradient" } },
16349
- required: ["type", "gradient"],
16350
- additionalProperties: false
16351
- },
16352
- {
16353
- type: "object",
16354
- properties: {
16355
- type: { const: "pattern", description: "Pattern (strokes only)." },
16356
- patternId: { type: "string", description: "Pattern id from list_layer_effects.patterns." },
16357
- name: { type: "string", description: "Display name." },
16358
- scale: { type: "number", minimum: 0.01, maximum: 10, description: "1 = 100 %." },
16359
- angle: { type: "number", minimum: -360, maximum: 360, description: "Rotation in degrees (default 0)." },
16360
- link: { type: "boolean", description: "Tile from the layer (default true) or the canvas origin." },
16361
- phase: { $ref: "#/$defs/phase" }
16362
- },
16363
- required: ["type", "patternId", "scale"],
16364
- additionalProperties: false
16365
- }
16366
- ]
16367
- }
16368
- };
16369
- var nullable = (schema, description) => ({ anyOf: [schema, { type: "null" }], description });
16370
- function settingsSchema(forUpdate) {
16371
- const opt2 = (schema, description) => forUpdate ? nullable(schema, `${description} null removes it.`) : { ...schema, description };
16372
- return {
16373
- type: "object",
16374
- description: forUpdate ? "Settings to change (only these; nested objects are replaced whole). Which settings a kind takes: see add_layer_effect." : "Settings to change from Photoshop's defaults (all optional). Unknown settings for the kind are refused with the list of its settings.",
16375
- properties: {
16376
- enabled: { type: "boolean", description: "All kinds: false keeps the effect but hides it (default true)." },
16377
- blend: { type: "string", enum: BLEND_IDS, description: "All but bevel-emboss: blend mode (shadows multiply, glows screen, others normal)." },
16378
- opacity: { type: "number", minimum: 0, maximum: 1, description: "All but bevel-emboss: 0..1 (shadows / glows 0.75, satin 0.5, others 1)." },
16379
- color: { $ref: "#/$defs/color", description: "drop-shadow, inner-shadow, satin, color-overlay: #rrggbb." },
16380
- angle: { type: "number", minimum: -360, maximum: 360, description: "Shadows, satin, bevel-emboss: light direction in degrees, counter-clockwise from 3 o'clock (default 120; satin 19)." },
16381
- useGlobalLight: { type: "boolean", description: "Shadows, bevel-emboss: follow the document global light instead of angle (default true)." },
16382
- distance: { type: "number", minimum: 0, maximum: 3e4, description: "Shadows, satin: offset in px (default 5; satin 11)." },
16383
- spread: { type: "number", minimum: 0, maximum: 1, description: "drop-shadow, outer-glow: 0..1 of the size made solid (default 0)." },
16384
- choke: { type: "number", minimum: 0, maximum: 1, description: "inner-shadow, inner-glow: 0..1 of the size made solid (default 0)." },
16385
- size: { type: "number", minimum: 0, maximum: 250, description: "Shadows, glows, satin, bevel-emboss: blur / size in px (default 5; satin 14); stroke: width in px (default 3)." },
16386
- contour: opt2({ $ref: "#/$defs/contour" }, "Shadows, glows, satin: coverage contour (default linear)."),
16387
- antiAlias: { type: "boolean", description: "Shadows, glows, satin: smooth the contour (default false; satin true)." },
16388
- noise: { type: "number", minimum: 0, maximum: 1, description: "Shadows, glows: speckle 0..1 (default 0)." },
16389
- knocksOut: { type: "boolean", description: "drop-shadow: the layer hides the shadow beneath its see-through fill (default true)." },
16390
- fill: { $ref: "#/$defs/fill", description: "outer-glow, inner-glow (color or gradient), stroke (color, gradient or pattern)." },
16391
- technique: { type: "string", enum: ["softer", "precise", "smooth", "chisel-hard", "chisel-soft"], description: "Glows: softer | precise (default softer); bevel-emboss: smooth | chisel-hard | chisel-soft (default smooth)." },
16392
- range: { type: "number", minimum: 0.01, maximum: 1, description: "Glows: the part of the glow the contour spans (default 0.5)." },
16393
- jitter: { type: "number", minimum: 0, maximum: 1, description: "Glows: gradient jitter 0..1 (stored, not rendered; default 0)." },
16394
- source: { type: "string", enum: ["edge", "center"], description: "inner-glow: glow from the edge (default) or the centre." },
16395
- style: { type: "string", enum: ["inner-bevel", "outer-bevel", "emboss", "pillow-emboss", "stroke-emboss"], description: "bevel-emboss: style (default inner-bevel)." },
16396
- depth: { type: "number", minimum: 0, maximum: 10, description: "bevel-emboss: depth, 1 = 100 % (default 1)." },
16397
- direction: { type: "string", enum: ["up", "down"], description: "bevel-emboss: raised (up, default) or sunk (down)." },
16398
- soften: { type: "number", minimum: 0, maximum: 16, description: "bevel-emboss: blur of the height in px (default 0)." },
16399
- altitude: { type: "number", minimum: 0, maximum: 90, description: "bevel-emboss: light altitude in degrees (default 30)." },
16400
- glossContour: opt2({ $ref: "#/$defs/contour" }, "bevel-emboss: gloss contour over the shading (default linear)."),
16401
- highlightColor: { $ref: "#/$defs/color", description: "bevel-emboss: highlight colour (default #ffffff)." },
16402
- highlightBlend: { type: "string", enum: BLEND_IDS, description: "bevel-emboss: highlight mode (default screen)." },
16403
- highlightOpacity: { type: "number", minimum: 0, maximum: 1, description: "bevel-emboss: highlight opacity (default 0.75)." },
16404
- shadowColor: { $ref: "#/$defs/color", description: "bevel-emboss: shadow colour (default #000000)." },
16405
- shadowBlend: { type: "string", enum: BLEND_IDS, description: "bevel-emboss: shadow mode (default multiply)." },
16406
- shadowOpacity: { type: "number", minimum: 0, maximum: 1, description: "bevel-emboss: shadow opacity (default 0.75)." },
16407
- contourElement: opt2(
16408
- {
16409
- type: "object",
16410
- properties: {
16411
- contour: { $ref: "#/$defs/contour" },
16412
- range: { type: "number", minimum: 0, maximum: 1, description: "Stored range (default 0.5)." },
16413
- antiAlias: { type: "boolean", description: "Smooth the contour." }
16414
- },
16415
- required: ["contour", "range", "antiAlias"],
16416
- additionalProperties: false
16417
- },
16418
- "bevel-emboss: the Contour element, shaping the bevel's height profile (default off)."
16419
- ),
16420
- texture: opt2(
16421
- {
16422
- type: "object",
16423
- properties: {
16424
- patternId: { type: "string", description: "Pattern id from list_layer_effects.patterns." },
16425
- name: { type: "string", description: "Display name." },
16426
- scale: { type: "number", minimum: 0.01, maximum: 10, description: "1 = 100 %." },
16427
- depth: { type: "number", minimum: -10, maximum: 10, description: "1 = +100 %; negative carves the pattern in." },
16428
- invert: { type: "boolean", description: "Invert the pattern." },
16429
- link: { type: "boolean", description: "Tile from the layer (default true)." },
16430
- phase: { $ref: "#/$defs/phase" }
16431
- },
16432
- required: ["patternId", "scale", "depth", "invert"],
16433
- additionalProperties: false
16434
- },
16435
- "bevel-emboss: the Texture element, a pattern's luminance as extra height (default off)."
16436
- ),
16437
- invert: { type: "boolean", description: "satin: invert (default true)." },
16438
- gradient: { $ref: "#/$defs/gradient", description: "gradient-overlay: the gradient (default black to white, 90\xB0)." },
16439
- dither: { type: "boolean", description: "gradient-overlay: dither (stored; default false)." },
16440
- patternId: { type: "string", description: "pattern-overlay: pattern id from list_layer_effects.patterns (default checker)." },
16441
- name: { type: "string", description: "pattern-overlay: pattern display name." },
16442
- scale: { type: "number", minimum: 0.01, maximum: 10, description: "pattern-overlay: 1 = 100 % (default 1)." },
16443
- link: { type: "boolean", description: "pattern-overlay: tile from the layer (default true) or the canvas origin." },
16444
- phase: { $ref: "#/$defs/phase", description: "pattern-overlay: origin offset in px (default 0, 0)." },
16445
- position: { type: "string", enum: ["outside", "inside", "center"], description: "stroke: where the stroke sits on the edge (default outside)." }
16446
- },
16447
- additionalProperties: false
16448
- };
16449
- }
16450
- function patternList(controller) {
16451
- const doc = controller.getDocumentPatterns().map((p) => ({ id: p.id, name: p.name, width: p.width, height: p.height, builtin: false }));
16452
- const builtins = builtinPatternIds().map((id) => {
16453
- const p = builtinPattern(id);
16454
- return { id, name: p.name, width: p.width, height: p.height, builtin: true };
16455
- });
16456
- return [...doc, ...builtins];
16457
- }
16458
- function describeLayerEffects(effects) {
16459
- return {
16460
- enabled: effects.enabled,
16461
- scale: effects.scale ?? 1,
16462
- margin: effectsMargin(effects),
16463
- fromPsd: Boolean(effects.psd),
16464
- effects: effects.items.map((e) => ({ ...JSON.parse(JSON.stringify(e)), label: layerEffectLabel(e.kind) }))
16465
- };
16466
- }
16467
- function createImageEffectTools(controller) {
16468
- const layerArg = (id) => {
16469
- if (typeof id !== "string" || !id) throw new LayerOperationError("layerId is required (a layer id from list_layers).");
16470
- requireLayer(controller.getLayers(), id);
16471
- return id;
16472
- };
16473
- const result = (layerId, extra = {}) => ({ layerId, ...extra, ...describeLayerEffects(controller.getLayerEffects(layerId)) });
16474
- const list = {
16475
- name: "list_layer_effects",
16476
- title: "List layer effects",
16477
- description: "Returns a layer's effects: the master switch (enabled), Scale Effects (scale, 1 = 100 %), margin (px the effects reach beyond the shape), whether they came from a PSD, and every effect with its id, kind, label and all settings. Also returns the document global light and the pattern ids pattern effects can use.",
16478
- inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
16479
- annotations: { title: "List layer effects", ...READ3 },
16480
- handler: ({ layerId }) => result(layerArg(layerId), { globalLight: controller.getGlobalLight(), patterns: patternList(controller), kinds: [...LAYER_EFFECT_KINDS] })
16481
- };
16482
- const add2 = {
16483
- name: "add_layer_effect",
16484
- title: "Add a layer effect",
16485
- description: "Adds a live effect to a pixel, shape, type, smart object, annotation or group layer with Photoshop's defaults, changed by settings: drop-shadow, inner-shadow, outer-glow, inner-glow, bevel-emboss, satin, color-overlay, gradient-overlay, pattern-overlay or stroke. Several of one kind are allowed (the first listed is on top). One undo step. Returns the new effect's id and the layer's effects.",
16486
- inputSchema: {
16487
- type: "object",
16488
- $defs: DEFS,
16489
- properties: {
16490
- layerId: LAYER_ID3,
16491
- kind: { type: "string", enum: [...LAYER_EFFECT_KINDS], description: "Effect kind." },
16492
- settings: settingsSchema(false),
16493
- index: { type: "integer", minimum: 0, description: "Position in the layer's effect list (default the end)." }
16494
- },
16495
- required: ["layerId", "kind"],
16496
- additionalProperties: false
16497
- },
16498
- annotations: { title: "Add a layer effect", ...WRITE3 },
16499
- handler: ({ layerId, kind, settings, index }) => {
16500
- const id = layerArg(layerId);
16501
- if (!isLayerEffectKind(kind)) throw new LayerOperationError(`kind must be one of ${LAYER_EFFECT_KINDS.join(", ")}.`);
16502
- const { effect } = controller.addLayerEffect(id, kind, settings ?? {}, index);
16503
- return result(id, { effectId: effect.id });
16504
- }
16505
- };
16506
- const update = {
16507
- name: "update_layer_effect",
16508
- title: "Change a layer effect",
16509
- description: "Changes settings of one effect (only the given ones; fill, gradient, contour and texture objects are replaced whole, null removes an optional contour or texture). The kind cannot change. Validates everything before changing anything. One undo step. Returns the layer's effects.",
16510
- inputSchema: {
16511
- type: "object",
16512
- $defs: DEFS,
16513
- properties: { layerId: LAYER_ID3, effectId: EFFECT_ID, settings: settingsSchema(true) },
16514
- required: ["layerId", "effectId", "settings"],
16515
- additionalProperties: false
16516
- },
16517
- annotations: { title: "Change a layer effect", ...WRITE_IDEMPOTENT3 },
16518
- handler: ({ layerId, effectId, settings }) => {
16519
- const id = layerArg(layerId);
16520
- const changes = settings ?? {};
16521
- if (!Object.keys(changes).length) throw new LayerOperationError("Give at least one setting to change.");
16522
- controller.updateLayerEffect(id, effectId, changes);
16523
- return result(id);
16524
- }
16525
- };
16526
- const remove = {
16527
- name: "remove_layer_effect",
16528
- title: "Remove a layer effect",
16529
- description: "Removes one effect from a layer (to hide it but keep its settings, set enabled false with update_layer_effect instead). One undo step. Returns the layer's remaining effects.",
16530
- inputSchema: { type: "object", properties: { layerId: LAYER_ID3, effectId: EFFECT_ID }, required: ["layerId", "effectId"], additionalProperties: false },
16531
- annotations: { title: "Remove a layer effect", ...DESTRUCTIVE2 },
16532
- handler: ({ layerId, effectId }) => {
16533
- const id = layerArg(layerId);
16534
- controller.removeLayerEffect(id, effectId);
16535
- return result(id);
16536
- }
16537
- };
16538
- const setEnabled = {
16539
- name: "set_layer_effects_enabled",
16540
- title: "Switch layer effects on or off",
16541
- description: "Turns all of a layer's effects on or off at once (the master switch; each effect keeps its own enabled flag) and optionally sets Scale Effects, which multiplies every size, distance and pattern scale. One undo step. Returns the layer's effects.",
16542
- inputSchema: {
16543
- type: "object",
16544
- properties: {
16545
- layerId: LAYER_ID3,
16546
- enabled: { type: "boolean", description: "true renders the enabled effects; false hides them all." },
16547
- scale: { type: "number", minimum: 0.01, maximum: 10, description: "Scale Effects, 1 = 100 % (unchanged when left out)." }
16548
- },
16549
- required: ["layerId", "enabled"],
16550
- additionalProperties: false
16551
- },
16552
- annotations: { title: "Switch layer effects on or off", ...WRITE_IDEMPOTENT3 },
16553
- handler: ({ layerId, enabled, scale }) => {
16554
- const id = layerArg(layerId);
16555
- controller.setLayerEffectsEnabled(id, enabled, scale);
16556
- return result(id);
16557
- }
16558
- };
16559
- const light = {
16560
- name: "set_global_light",
16561
- title: "Set the global light",
16562
- description: "Sets the document global light that shadows and bevels with useGlobalLight follow (Photoshop default: angle 120\xB0, altitude 30\xB0). One undo step. Returns the light.",
16563
- inputSchema: {
16564
- type: "object",
16565
- properties: {
16566
- angle: { type: "number", minimum: -360, maximum: 360, description: "Degrees, counter-clockwise from 3 o'clock: where the light comes from (unchanged when left out)." },
16567
- altitude: { type: "number", minimum: 0, maximum: 90, description: "Degrees above the canvas, for bevels (unchanged when left out)." }
16568
- },
16569
- additionalProperties: false
16570
- },
16571
- annotations: { title: "Set the global light", ...WRITE_IDEMPOTENT3 },
16572
- handler: ({ angle, altitude }) => {
16573
- if (angle === void 0 && altitude === void 0) throw new LayerOperationError("Give angle, altitude or both.");
16574
- const next = {};
16575
- if (angle !== void 0) next.angle = angle;
16576
- if (altitude !== void 0) next.altitude = altitude;
16577
- return { globalLight: controller.setGlobalLight(next) };
16578
- }
16579
- };
16580
- return [list, add2, update, remove, setEnabled, light];
16581
- }
16582
-
16583
16262
  // src/image-editor/selection/gesture.ts
16584
16263
  function snapTo45(from, point2) {
16585
16264
  const dx = point2.x - from.x;
@@ -17315,10 +16994,10 @@ var PaintGesture = class {
17315
16994
  };
17316
16995
 
17317
16996
  // src/image-editor/paint-tools.ts
17318
- var READ4 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17319
- var WRITE4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
16997
+ var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
16998
+ var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17320
16999
  var SET = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17321
- var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
17000
+ var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
17322
17001
  var TARGET = {
17323
17002
  layerId: { type: "string", description: "Layer to paint (default the active layer; see list_layers)." },
17324
17003
  channel: {
@@ -17408,7 +17087,7 @@ function createImagePaintTools(controller) {
17408
17087
  required: ["points"],
17409
17088
  additionalProperties: false
17410
17089
  },
17411
- annotations: { title: "Paint a brush stroke", ...WRITE4 },
17090
+ annotations: { title: "Paint a brush stroke", ...WRITE3 },
17412
17091
  handler: (args) => {
17413
17092
  const tool = args.tool;
17414
17093
  if (args.mixer !== void 0 && tool !== "mixer") throw new LayerOperationError('mixer settings apply to the Mixer Brush only; pass tool "mixer", or drop mixer.');
@@ -17431,7 +17110,7 @@ function createImagePaintTools(controller) {
17431
17110
  title: "Get the Mixer Brush",
17432
17111
  description: "Reads the Mixer Brush: its settings (wet, load, mix, loadEachStroke, cleanEachStroke, mixing) and what it carries now (reservoir #rrggbb or null, amount 0..1 left, pickup #rrggbb or null). Call it before a paint_stroke with tool mixer and loadEachStroke false, to know the brush's starting paint.",
17433
17112
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17434
- annotations: { title: "Get the Mixer Brush", ...READ4 },
17113
+ annotations: { title: "Get the Mixer Brush", ...READ3 },
17435
17114
  handler: () => {
17436
17115
  const { mixer, mixerLoad } = controller.getState().paint;
17437
17116
  return { settings: { ...mixer }, load: mixerLoadResult(mixerLoad) };
@@ -17446,7 +17125,7 @@ function createImagePaintTools(controller) {
17446
17125
  properties: { color: { type: "string", description: "Paint colour #rrggbb (default the foreground)." } },
17447
17126
  additionalProperties: false
17448
17127
  },
17449
- annotations: { title: "Load the Mixer Brush", ...WRITE4, idempotentHint: true },
17128
+ annotations: { title: "Load the Mixer Brush", ...WRITE3, idempotentHint: true },
17450
17129
  handler: (args) => mixerLoadResult(controller.loadMixerBrush(args.color))
17451
17130
  };
17452
17131
  const cleanMixerTool = {
@@ -17458,7 +17137,7 @@ function createImagePaintTools(controller) {
17458
17137
  properties: { emptyReservoir: { type: "boolean", description: "Also drop the reservoir (default false)." } },
17459
17138
  additionalProperties: false
17460
17139
  },
17461
- annotations: { title: "Clean the Mixer Brush", ...WRITE4, idempotentHint: true },
17140
+ annotations: { title: "Clean the Mixer Brush", ...WRITE3, idempotentHint: true },
17462
17141
  handler: (args) => mixerLoadResult(args.emptyReservoir === true ? controller.emptyMixerBrush() : controller.cleanMixerBrush())
17463
17142
  };
17464
17143
  const fill = {
@@ -17476,7 +17155,7 @@ function createImagePaintTools(controller) {
17476
17155
  },
17477
17156
  additionalProperties: false
17478
17157
  },
17479
- annotations: { title: "Fill pixels", ...WRITE4 },
17158
+ annotations: { title: "Fill pixels", ...WRITE3 },
17480
17159
  handler: (args) => controller.fillPixels({
17481
17160
  color: args.color,
17482
17161
  opacity: args.opacity,
@@ -17498,7 +17177,7 @@ function createImagePaintTools(controller) {
17498
17177
  },
17499
17178
  additionalProperties: false
17500
17179
  },
17501
- annotations: { title: "Clear pixels", ...DESTRUCTIVE3 },
17180
+ annotations: { title: "Clear pixels", ...DESTRUCTIVE2 },
17502
17181
  handler: (args) => controller.clearPixels({ opacity: args.opacity, useSelection: args.useSelection, ...readTarget(args) })
17503
17182
  };
17504
17183
  const paintView = () => {
@@ -17521,7 +17200,7 @@ function createImagePaintTools(controller) {
17521
17200
  title: "Get the paint",
17522
17201
  description: "Reads what the brush paints (paint: the foreground colour or gradient paint), the foreground and background colours and the brush settings (size, hardness, spacing, opacity, flow \u2026). Changes nothing.",
17523
17202
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17524
- annotations: { title: "Get the paint", ...READ4 },
17203
+ annotations: { title: "Get the paint", ...READ3 },
17525
17204
  handler: () => paintView()
17526
17205
  };
17527
17206
  const sampleColor2 = {
@@ -17564,7 +17243,7 @@ function createImagePaintTools(controller) {
17564
17243
  required: ["start", "end"],
17565
17244
  additionalProperties: false
17566
17245
  },
17567
- annotations: { title: "Sample a gradient along a line", ...READ4 },
17246
+ annotations: { title: "Sample a gradient along a line", ...READ3 },
17568
17247
  handler: (args) => {
17569
17248
  const start = args.start;
17570
17249
  const end = args.end;
@@ -17593,7 +17272,7 @@ function createImagePaintTools(controller) {
17593
17272
  }
17594
17273
 
17595
17274
  // src/image-editor/color-tools.ts
17596
- var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17275
+ var READ4 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17597
17276
  var PROFILE = {
17598
17277
  type: "string",
17599
17278
  description: `A built-in profile id (${BUILTIN_PROFILES.map((b) => b.id).join(", ")}; names like "Adobe RGB (1998)" work too), or "icc:<base64>" for ICC profile bytes.`
@@ -17620,7 +17299,7 @@ function createImageColorTools(controller) {
17620
17299
  title: "Get the colour profile",
17621
17300
  description: "Reads the document's colour profile (its working space: name, builtin id or null for an embedded profile, colorSpace, srgb true when it means sRGB, mode rgb / cmyk / lab and, for cmyk, cmykProfile), the Proof Setup (profile, intent, bpc, simulatePaper, gamutWarning, or null) and the built-in profiles you can assign, convert to or proof with ({id, description, colorSpace}).",
17622
17301
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17623
- annotations: { title: "Get the colour profile", ...READ5 },
17302
+ annotations: { title: "Get the colour profile", ...READ4 },
17624
17303
  handler: () => {
17625
17304
  const proof2 = controller.getState().proofSetup;
17626
17305
  return {
@@ -17704,7 +17383,7 @@ function createImageColorTools(controller) {
17704
17383
  required: ["colors", "to"],
17705
17384
  additionalProperties: false
17706
17385
  },
17707
- annotations: { title: "Convert colours between profiles", ...READ5 },
17386
+ annotations: { title: "Convert colours between profiles", ...READ4 },
17708
17387
  handler: (args) => ({
17709
17388
  colors: controller.convertColors(args.colors, profileArg(args.to), {
17710
17389
  ...args.from !== void 0 ? { from: profileArg(args.from) } : {},
@@ -17740,8 +17419,8 @@ function createImageColorTools(controller) {
17740
17419
  }
17741
17420
 
17742
17421
  // src/image-editor/retouch-tools.ts
17743
- var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17744
- var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17422
+ var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17423
+ var WRITE4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17745
17424
  var POINTS = {
17746
17425
  type: "array",
17747
17426
  minItems: 1,
@@ -17831,7 +17510,7 @@ function createImageRetouchTools(controller) {
17831
17510
  required: ["points"],
17832
17511
  additionalProperties: false
17833
17512
  },
17834
- annotations: { title: "Clone Stamp stroke", ...WRITE5 },
17513
+ annotations: { title: "Clone Stamp stroke", ...WRITE4 },
17835
17514
  handler: (args) => stroke("clone", args, pick(args, ["aligned", "sample"]))
17836
17515
  };
17837
17516
  const healBrush = {
@@ -17851,7 +17530,7 @@ function createImageRetouchTools(controller) {
17851
17530
  required: ["points"],
17852
17531
  additionalProperties: false
17853
17532
  },
17854
- annotations: { title: "Healing Brush stroke", ...WRITE5 },
17533
+ annotations: { title: "Healing Brush stroke", ...WRITE4 },
17855
17534
  handler: (args) => stroke("heal", args, pick(args, ["aligned", "sample"]))
17856
17535
  };
17857
17536
  const spotHeal = {
@@ -17870,7 +17549,7 @@ function createImageRetouchTools(controller) {
17870
17549
  required: ["points"],
17871
17550
  additionalProperties: false
17872
17551
  },
17873
- annotations: { title: "Spot Healing stroke", ...WRITE5 },
17552
+ annotations: { title: "Spot Healing stroke", ...WRITE4 },
17874
17553
  handler: (args) => stroke("spot-heal", args, { ...pick(args, ["sample"]), ...args.type !== void 0 ? { spotType: args.type } : {} })
17875
17554
  };
17876
17555
  const smudge = {
@@ -17888,7 +17567,7 @@ function createImageRetouchTools(controller) {
17888
17567
  required: ["points"],
17889
17568
  additionalProperties: false
17890
17569
  },
17891
- annotations: { title: "Smudge stroke", ...WRITE5 },
17570
+ annotations: { title: "Smudge stroke", ...WRITE4 },
17892
17571
  handler: (args) => stroke("smudge", args, pick(args, ["strength"]))
17893
17572
  };
17894
17573
  const toneSchema = (verb) => ({
@@ -17909,7 +17588,7 @@ function createImageRetouchTools(controller) {
17909
17588
  title: "Dodge stroke",
17910
17589
  description: "Lightens the pixels a stroke covers (Photoshop's Dodge), most in the chosen tonal range. Alpha is kept. One undo step. Returns the layerId, channel, changed bounds and dab count. Inspect the result with capture_view or get_histogram; several light strokes look more natural than one strong one.",
17911
17590
  inputSchema: toneSchema("lighten"),
17912
- annotations: { title: "Dodge stroke", ...WRITE5 },
17591
+ annotations: { title: "Dodge stroke", ...WRITE4 },
17913
17592
  handler: (args) => stroke("dodge", args, pick(args, ["range", "exposure", "protectTones"]))
17914
17593
  };
17915
17594
  const burn = {
@@ -17917,7 +17596,7 @@ function createImageRetouchTools(controller) {
17917
17596
  title: "Burn stroke",
17918
17597
  description: "Darkens the pixels a stroke covers (Photoshop's Burn), most in the chosen tonal range. Alpha is kept. One undo step. Returns the layerId, channel, changed bounds and dab count.",
17919
17598
  inputSchema: toneSchema("darken"),
17920
- annotations: { title: "Burn stroke", ...WRITE5 },
17599
+ annotations: { title: "Burn stroke", ...WRITE4 },
17921
17600
  handler: (args) => stroke("burn", args, pick(args, ["range", "exposure", "protectTones"]))
17922
17601
  };
17923
17602
  const spongeTool = {
@@ -17936,7 +17615,7 @@ function createImageRetouchTools(controller) {
17936
17615
  required: ["points"],
17937
17616
  additionalProperties: false
17938
17617
  },
17939
- annotations: { title: "Sponge stroke", ...WRITE5 },
17618
+ annotations: { title: "Sponge stroke", ...WRITE4 },
17940
17619
  handler: (args) => stroke("sponge", { ...args, channel: "pixels" }, { ...pick(args, ["vibrance"]), ...args.mode !== void 0 ? { spongeMode: args.mode } : {} })
17941
17620
  };
17942
17621
  const filterSchema = (verb) => ({
@@ -17955,7 +17634,7 @@ function createImageRetouchTools(controller) {
17955
17634
  title: "Blur stroke",
17956
17635
  description: "Softens the pixels a stroke covers (Photoshop's Blur tool): a soft blur of the layer laid through the brush at `strength`. Overlapping dabs in one stroke do not compound; another stroke blurs further. Works on pixels and masks, at any bit depth. One undo step. Returns the layerId, channel, changed bounds and dab count.",
17957
17636
  inputSchema: filterSchema("blur"),
17958
- annotations: { title: "Blur stroke", ...WRITE5 },
17637
+ annotations: { title: "Blur stroke", ...WRITE4 },
17959
17638
  handler: (args) => stroke("blur", args, pick(args, ["strength"]))
17960
17639
  };
17961
17640
  const sharpenTool = {
@@ -17963,7 +17642,7 @@ function createImageRetouchTools(controller) {
17963
17642
  title: "Sharpen stroke",
17964
17643
  description: "Crisps the pixels a stroke covers (Photoshop's Sharpen tool): an unsharp mask of the layer laid through the brush at `strength`. Keep strength low (0.2..0.5) and inspect with capture_view; strong sharpening shows halos and noise. One undo step. Returns the layerId, channel, changed bounds and dab count.",
17965
17644
  inputSchema: filterSchema("sharpen"),
17966
- annotations: { title: "Sharpen stroke", ...WRITE5 },
17645
+ annotations: { title: "Sharpen stroke", ...WRITE4 },
17967
17646
  handler: (args) => stroke("sharpen", args, pick(args, ["strength"]))
17968
17647
  };
17969
17648
  const historyBrush = {
@@ -17981,7 +17660,7 @@ function createImageRetouchTools(controller) {
17981
17660
  required: ["points"],
17982
17661
  additionalProperties: false
17983
17662
  },
17984
- annotations: { title: "History Brush stroke", ...WRITE5 },
17663
+ annotations: { title: "History Brush stroke", ...WRITE4 },
17985
17664
  handler: (args) => stroke("history", args, pick(args, ["historySteps"]))
17986
17665
  };
17987
17666
  const getOptions = {
@@ -17989,7 +17668,7 @@ function createImageRetouchTools(controller) {
17989
17668
  title: "Get retouch options",
17990
17669
  description: "Reads the retouching tools' options (aligned, sample, spotType, range, exposure, protectTones, spongeMode, vibrance, strength, historySteps), the Clone Source transform ({scaleX, scaleY, rotate}) and the clone source ({x, y, offset} or null; offset is the aligned offset the last clone or heal stroke fixed: an aligned stroke samples at the brush plus offset, which the editors show as a crosshair). Call it before clone_stamp or heal_brush without a source to see where they will sample.",
17991
17670
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17992
- annotations: { title: "Get retouch options", ...READ6 },
17671
+ annotations: { title: "Get retouch options", ...READ5 },
17993
17672
  handler: () => {
17994
17673
  const { retouch, cloneSource, cloneTransform } = controller.getState().paint;
17995
17674
  return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null, cloneTransform: { ...cloneTransform } };
@@ -18015,7 +17694,7 @@ function createImageRetouchTools(controller) {
18015
17694
  },
18016
17695
  additionalProperties: false
18017
17696
  },
18018
- annotations: { title: "Set retouch options", ...WRITE5, idempotentHint: true },
17697
+ annotations: { title: "Set retouch options", ...WRITE4, idempotentHint: true },
18019
17698
  handler: (args) => ({ ...controller.setPaintOptions({ retouch: args }).retouch })
18020
17699
  };
18021
17700
  const setSource = {
@@ -18031,7 +17710,7 @@ function createImageRetouchTools(controller) {
18031
17710
  },
18032
17711
  additionalProperties: false
18033
17712
  },
18034
- annotations: { title: "Set the clone source", ...WRITE5, idempotentHint: true },
17713
+ annotations: { title: "Set the clone source", ...WRITE4, idempotentHint: true },
18035
17714
  handler: (args) => {
18036
17715
  if (args.clear === true) {
18037
17716
  if (args.x !== void 0 || args.y !== void 0) throw new LayerOperationError("Give either clear true or x and y, not both.");
@@ -18057,7 +17736,7 @@ function createImageRetouchTools(controller) {
18057
17736
  },
18058
17737
  additionalProperties: false
18059
17738
  },
18060
- annotations: { title: "Transform the clone source", ...WRITE5, idempotentHint: false },
17739
+ annotations: { title: "Transform the clone source", ...WRITE4, idempotentHint: false },
18061
17740
  handler: (args) => {
18062
17741
  if (args.reset === true) {
18063
17742
  if (Object.keys(args).some((k) => k !== "reset")) throw new LayerOperationError("Give either reset true or transform values, not both.");
@@ -18083,8 +17762,8 @@ function pick(args, keys) {
18083
17762
  }
18084
17763
 
18085
17764
  // src/image-editor/psd-tools.ts
18086
- var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18087
- var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
17765
+ var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17766
+ var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18088
17767
  var DATA = {
18089
17768
  type: "string",
18090
17769
  minLength: 1,
@@ -18104,7 +17783,7 @@ function createImagePsdTools(controller) {
18104
17783
  title: "Inspect a PSD",
18105
17784
  description: "Reads a PSD / PSB without opening it: size, bit depth, colour mode, resolution, and every layer (bottom first, a group before its children) with its PSD kind, the layer type it would become and its status (mapped, approximated or dropped, with notes), plus the import warnings. Changes nothing. Call before import_psd to see what would be lost.",
18106
17785
  inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
18107
- annotations: { title: "Inspect a PSD", ...READ7 },
17786
+ annotations: { title: "Inspect a PSD", ...READ6 },
18108
17787
  handler: ({ data }) => {
18109
17788
  const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
18110
17789
  return {
@@ -18122,7 +17801,7 @@ function createImagePsdTools(controller) {
18122
17801
  title: "Open a PSD as the document",
18123
17802
  description: "Opens a PSD / PSB as the document, replacing the current layers, crop and rotation (one undo step; undo brings the previous document back). Pixel, group and adjustment layers, masks, blend modes, opacity, fill, clipping, visibility, locks, layer effects (with the patterns and global light of the file) map directly; smart objects come in as smart objects (embedded contents, placement and warp, smart filters: Box Blur is drawn, other Photoshop filters are kept but not drawn, filter mask; linked contents as their stored pixels); shape layers come in as live shapes (paths, path operations, fill, stroke, live rectangles, ellipses and lines); type layers come in as live text (runs, paragraphs, frame, transform) showing Photoshop\u2019s pixels until edited, with a warning for fonts missing here; fill layers come in as their pixels; unsupported adjustments are left out. Returns the new layer tree with ids, the size and the warnings (each names the affected layers).",
18124
17803
  inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
18125
- annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE4 },
17804
+ annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE3 },
18126
17805
  handler: ({ data }) => {
18127
17806
  const res = controller.loadPsd(psdBytesFromBase64(data));
18128
17807
  const s = controller.getState();
@@ -18141,7 +17820,7 @@ function createImagePsdTools(controller) {
18141
17820
  title: "Export the document as a PSD",
18142
17821
  description: "Writes the document as an RGB PSD at its bit depth (8, 16 or 32; see set_bit_depth; a PSB above 30000 px) with real layers, groups, adjustment layers, masks and layer effects (an effects block opened from a PSD is written back unchanged while its effects are; the patterns effects use are embedded), in the source frame (crop and rotation are not applied). Smart objects are written as Photoshop smart objects (contents embedded once per linked set, placement, warp, smart filters and filter mask; a Develop smart filter has no Photoshop filter and is left out of the list). Shape layers are written as Photoshop shape layers (path, fill, stroke, live shapes) and type layers as Photoshop type layers (text, runs, paragraphs, frame; blocks opened from a PSD are written back unchanged while the layer is). Layer filters and depth masks are baked, annotation layers are rasterized (in a browser; elsewhere left out), and the merged image is the editor's composite. Changes nothing. Returns the file as base64, its size in bytes, whether it is a PSB, and warnings for everything that was changed or left out.",
18143
17822
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
18144
- annotations: { title: "Export the document as a PSD", ...READ7 },
17823
+ annotations: { title: "Export the document as a PSD", ...READ6 },
18145
17824
  handler: async () => {
18146
17825
  const res = await controller.toPsd();
18147
17826
  return {
@@ -18159,8 +17838,8 @@ function createImagePsdTools(controller) {
18159
17838
  }
18160
17839
 
18161
17840
  // src/image-editor/transform-tools.ts
18162
- var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18163
- var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17841
+ var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17842
+ var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18164
17843
  var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
18165
17844
  var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
18166
17845
  var POINT = {
@@ -18259,7 +17938,7 @@ function createImageTransformTools(controller) {
18259
17938
  },
18260
17939
  additionalProperties: false
18261
17940
  },
18262
- annotations: { title: "Get the Free Transform frame", ...READ8 },
17941
+ annotations: { title: "Get the Free Transform frame", ...READ7 },
18263
17942
  handler: (args) => {
18264
17943
  const init = targetFrom(args);
18265
17944
  if (init.content === "selection-copy") init.content = "selection";
@@ -18292,7 +17971,7 @@ function createImageTransformTools(controller) {
18292
17971
  properties: { ...TARGET3, ...GEOMETRY },
18293
17972
  additionalProperties: false
18294
17973
  },
18295
- annotations: { title: "Free Transform a layer", ...WRITE6 },
17974
+ annotations: { title: "Free Transform a layer", ...WRITE5 },
18296
17975
  handler: (args) => summary2(controller.transformLayer({ ...targetFrom(args), ...geometryFrom(args) }))
18297
17976
  };
18298
17977
  const warpLayer = {
@@ -18322,7 +18001,7 @@ function createImageTransformTools(controller) {
18322
18001
  },
18323
18002
  additionalProperties: false
18324
18003
  },
18325
- annotations: { title: "Warp a layer", ...WRITE6 },
18004
+ annotations: { title: "Warp a layer", ...WRITE5 },
18326
18005
  handler: (args) => {
18327
18006
  const hasPreset = ["style", "bend", "horizontal", "vertical", "orientation"].some((k) => args[k] !== void 0);
18328
18007
  if (hasPreset && args.mesh !== void 0) throw new LayerOperationError("Give a preset (style, bend, horizontal, vertical, orientation) or a mesh, not both.");
@@ -18356,7 +18035,7 @@ function createImageTransformTools(controller) {
18356
18035
  properties: { interpolation: { ...TARGET3.interpolation, description: "Resampling of soft edges: nearest, bilinear or bicubic (default)." }, ...GEOMETRY },
18357
18036
  additionalProperties: false
18358
18037
  },
18359
- annotations: { title: "Transform the selection outline", ...WRITE6 },
18038
+ annotations: { title: "Transform the selection outline", ...WRITE5 },
18360
18039
  handler: (args) => {
18361
18040
  const res = controller.transformLayer({ content: "selection-outline", interpolation: args.interpolation, ...geometryFrom(args) });
18362
18041
  return { changed: res.changed, frame: { ...res.box }, corners: res.corners.map(roundPoint), bounds: res.bounds };
@@ -18377,7 +18056,7 @@ function createImageTransformTools(controller) {
18377
18056
  required: ["axis"],
18378
18057
  additionalProperties: false
18379
18058
  },
18380
- annotations: { title: "Flip a layer", ...WRITE6 },
18059
+ annotations: { title: "Flip a layer", ...WRITE5 },
18381
18060
  handler: (args) => summary2(controller.flipLayer(args.axis, targetFrom(args)))
18382
18061
  };
18383
18062
  const rotate90 = {
@@ -18395,20 +18074,20 @@ function createImageTransformTools(controller) {
18395
18074
  required: ["turn"],
18396
18075
  additionalProperties: false
18397
18076
  },
18398
- annotations: { title: "Rotate a layer by quarter turns", ...WRITE6 },
18077
+ annotations: { title: "Rotate a layer by quarter turns", ...WRITE5 },
18399
18078
  handler: (args) => summary2(controller.rotateLayer90(args.turn, targetFrom(args)))
18400
18079
  };
18401
18080
  return [getFrame, transformLayer, warpLayer, transformSelection, flipLayer, rotate90];
18402
18081
  }
18403
18082
 
18404
18083
  // src/image-editor/smart-tools.ts
18405
- var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18406
- var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18407
- var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18408
- var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18084
+ var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18085
+ var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18086
+ var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18087
+ var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18409
18088
  var round5 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
18410
18089
  var roundPoint2 = (p) => ({ x: round5(p.x), y: round5(p.y) });
18411
- var LAYER_ID4 = { type: "string", description: "Smart object layer id from list_layers (type smart)." };
18090
+ var LAYER_ID3 = { type: "string", description: "Smart object layer id from list_layers (type smart)." };
18412
18091
  var FILTER_ID = { type: "string", description: "Smart filter id from get_smart_object or add_smart_filter." };
18413
18092
  var POINT2 = {
18414
18093
  type: "object",
@@ -18460,8 +18139,8 @@ function createImageSmartObjectTools(controller) {
18460
18139
  name: "get_smart_object",
18461
18140
  title: "Read a smart object",
18462
18141
  description: "Returns a smart object\u2019s contents (id shared by linked instances, name, kind raster or document, pixel size, the file type it came from, the instances placed from it), its placement (corners in document pixels, warp mesh in contents pixels, interpolation, and scale / rotate / skew in percent and degrees of the contents\u2019 own size when affine), its smart filters bottom to top (ids, kind, settings, enabled, blend, opacity; kind psd marks a Photoshop filter kept but not drawn) with the filter mask, and the rendered bounds. Changes nothing.",
18463
- inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18464
- annotations: { title: "Read a smart object", ...READ9 },
18142
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18143
+ annotations: { title: "Read a smart object", ...READ8 },
18465
18144
  handler: ({ layerId }) => info(smartId(layerId))
18466
18145
  };
18467
18146
  const convert = {
@@ -18476,7 +18155,7 @@ function createImageSmartObjectTools(controller) {
18476
18155
  },
18477
18156
  additionalProperties: false
18478
18157
  },
18479
- annotations: { title: "Convert to Smart Object", ...WRITE7 },
18158
+ annotations: { title: "Convert to Smart Object", ...WRITE6 },
18480
18159
  handler: ({ layerIds, name }) => {
18481
18160
  for (const id2 of layerIds ?? []) requireLayer(controller.getLayers(), id2);
18482
18161
  const id = controller.convertToSmartObject(layerIds, { name });
@@ -18487,8 +18166,8 @@ function createImageSmartObjectTools(controller) {
18487
18166
  name: "rasterize_smart_object",
18488
18167
  title: "Rasterize a smart object",
18489
18168
  description: "Layer \u203A Smart Objects \u203A Rasterize: the smart object becomes a pixel layer holding what it shows now (smart filters baked; same id, mask, effects, opacity, blend and fill). The contents, placement and filters are gone, so later transforms resample the pixels. One undo step. Returns the layer.",
18490
- inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18491
- annotations: { title: "Rasterize a smart object", ...DESTRUCTIVE5 },
18169
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18170
+ annotations: { title: "Rasterize a smart object", ...DESTRUCTIVE4 },
18492
18171
  handler: ({ layerId }) => ({ layer: layerSummary(controller.rasterizeSmartObject(smartId(layerId))) })
18493
18172
  };
18494
18173
  const setTransform = {
@@ -18498,7 +18177,7 @@ function createImageSmartObjectTools(controller) {
18498
18177
  inputSchema: {
18499
18178
  type: "object",
18500
18179
  properties: {
18501
- layerId: LAYER_ID4,
18180
+ layerId: LAYER_ID3,
18502
18181
  corners: { type: "array", items: POINT2, minItems: 4, maxItems: 4, description: "Where the contents\u2019 corners land: [top-left, top-right, bottom-right, bottom-left] in document pixels. The quad must stay convex." },
18503
18182
  matrix: { type: "array", items: { type: "number" }, minItems: 6, maxItems: 6, description: "Affine map from contents pixels to document pixels [a, b, c, d, e, f] (x' = a\xB7x + c\xB7y + e, y' = b\xB7x + d\xB7y + f)." },
18504
18183
  scaleX: { type: "number", description: "Width in percent of the contents\u2019 own width (negative flips)." },
@@ -18541,7 +18220,7 @@ function createImageSmartObjectTools(controller) {
18541
18220
  required: ["layerId"],
18542
18221
  additionalProperties: false
18543
18222
  },
18544
- annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT4 },
18223
+ annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT3 },
18545
18224
  handler: (args) => {
18546
18225
  const id = smartId(args.layerId);
18547
18226
  let warp;
@@ -18580,22 +18259,22 @@ function createImageSmartObjectTools(controller) {
18580
18259
  inputSchema: {
18581
18260
  type: "object",
18582
18261
  properties: {
18583
- layerId: LAYER_ID4,
18262
+ layerId: LAYER_ID3,
18584
18263
  image: { type: "string", description: "The new contents: a PNG as a data URL or base64 (other formats and URLs need a browser)." },
18585
18264
  name: { type: "string", description: "File name of the contents (default the old name with .png)." }
18586
18265
  },
18587
18266
  required: ["layerId", "image"],
18588
18267
  additionalProperties: false
18589
18268
  },
18590
- annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE5 },
18269
+ annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE4 },
18591
18270
  handler: async ({ layerId, image, name }) => controller.replaceSmartObjectContentsFromImage(smartId(layerId), imageArg(image), name)
18592
18271
  };
18593
18272
  const exportContents = {
18594
18273
  name: "export_smart_object_contents",
18595
18274
  title: "Export a smart object\u2019s contents",
18596
18275
  description: "Layer \u203A Smart Objects \u203A Export Contents: the contents as a file, base64: the file they came from while unedited (a PSB, PNG, JPEG\u2026), else a PNG for raster contents or a PSD / PSB of a nested document. Returns name, mimeType, byteLength and base64. Changes nothing.",
18597
- inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18598
- annotations: { title: "Export a smart object\u2019s contents", ...READ9 },
18276
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18277
+ annotations: { title: "Export a smart object\u2019s contents", ...READ8 },
18599
18278
  handler: ({ layerId }) => {
18600
18279
  const f = controller.exportSmartObjectContents(smartId(layerId));
18601
18280
  return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
@@ -18608,14 +18287,14 @@ function createImageSmartObjectTools(controller) {
18608
18287
  inputSchema: {
18609
18288
  type: "object",
18610
18289
  properties: {
18611
- layerId: LAYER_ID4,
18290
+ layerId: LAYER_ID3,
18612
18291
  linked: { type: "boolean", description: "true shares the contents with the original; false (default) makes independent contents." },
18613
18292
  name: { type: "string", description: 'Name of the copy (default "<name> copy").' }
18614
18293
  },
18615
18294
  required: ["layerId"],
18616
18295
  additionalProperties: false
18617
18296
  },
18618
- annotations: { title: "Copy a smart object", ...WRITE7 },
18297
+ annotations: { title: "Copy a smart object", ...WRITE6 },
18619
18298
  handler: ({ layerId, linked, name }) => {
18620
18299
  const id = controller.copySmartObject(smartId(layerId), linked === true, name);
18621
18300
  return { layer: layerSummary(id), contentsId: controller.getSmartObject(id).contents.id };
@@ -18625,8 +18304,8 @@ function createImageSmartObjectTools(controller) {
18625
18304
  name: "edit_smart_object_contents",
18626
18305
  title: "Edit a smart object\u2019s contents",
18627
18306
  description: 'Layer \u203A Smart Objects \u203A Edit Contents: opens the contents as a document of their own (a layer document, or raster contents as one pixel layer "Layer 0") with their own undo history. Every other tool (list_layers, paint, adjustments\u2026) then works inside the contents until close_smart_object_contents saves them back. Contents can nest. Returns the contents\u2019 size and layers.',
18628
- inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18629
- annotations: { title: "Edit a smart object\u2019s contents", ...WRITE7 },
18307
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18308
+ annotations: { title: "Edit a smart object\u2019s contents", ...WRITE6 },
18630
18309
  handler: ({ layerId }) => {
18631
18310
  const res = controller.editSmartObjectContents(smartId(layerId));
18632
18311
  const s = controller.getState();
@@ -18642,7 +18321,7 @@ function createImageSmartObjectTools(controller) {
18642
18321
  properties: { save: { type: "boolean", description: "true (default) saves the edits into the smart object; false discards them." } },
18643
18322
  additionalProperties: false
18644
18323
  },
18645
- annotations: { title: "Close a smart object\u2019s contents", ...WRITE7 },
18324
+ annotations: { title: "Close a smart object\u2019s contents", ...WRITE6 },
18646
18325
  handler: ({ save }) => ({ ...controller.closeSmartObjectContents(save !== false), editing: controller.getEditingContents() })
18647
18326
  };
18648
18327
  const addFilter = {
@@ -18652,7 +18331,7 @@ function createImageSmartObjectTools(controller) {
18652
18331
  inputSchema: {
18653
18332
  type: "object",
18654
18333
  properties: {
18655
- layerId: LAYER_ID4,
18334
+ layerId: LAYER_ID3,
18656
18335
  kind: { type: "string", enum: ["develop", "blur"], description: "Filter kind." },
18657
18336
  index: { type: "integer", minimum: 0, description: "Position in the stack, 0 = bottom, applied first (default the top)." },
18658
18337
  useSelection: { type: "boolean", description: "With a selection, set the filter mask from it so the filter only changes the selected area (default true)." },
@@ -18661,7 +18340,7 @@ function createImageSmartObjectTools(controller) {
18661
18340
  required: ["layerId", "kind"],
18662
18341
  additionalProperties: false
18663
18342
  },
18664
- annotations: { title: "Add a smart filter", ...WRITE7 },
18343
+ annotations: { title: "Add a smart filter", ...WRITE6 },
18665
18344
  handler: (args) => {
18666
18345
  const id = smartId(args.layerId);
18667
18346
  const masked = args.useSelection !== false && controller.hasSelection;
@@ -18675,11 +18354,11 @@ function createImageSmartObjectTools(controller) {
18675
18354
  description: "Changes one smart filter: its settings, enabled, blend or opacity (only the given values; the kind cannot change). A Photoshop filter kept from a PSD (kind psd) only takes enabled, blend and opacity. One undo step. Returns the filter and the stack.",
18676
18355
  inputSchema: {
18677
18356
  type: "object",
18678
- properties: { layerId: LAYER_ID4, filterId: FILTER_ID, ...FILTER_SETTINGS },
18357
+ properties: { layerId: LAYER_ID3, filterId: FILTER_ID, ...FILTER_SETTINGS },
18679
18358
  required: ["layerId", "filterId"],
18680
18359
  additionalProperties: false
18681
18360
  },
18682
- annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT4 },
18361
+ annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT3 },
18683
18362
  handler: (args) => {
18684
18363
  const id = smartId(args.layerId);
18685
18364
  const changes = settingsFrom(args);
@@ -18692,8 +18371,8 @@ function createImageSmartObjectTools(controller) {
18692
18371
  name: "remove_smart_filter",
18693
18372
  title: "Remove a smart filter",
18694
18373
  description: "Removes one smart filter (the filter mask goes with the last one). One undo step. Returns the remaining stack.",
18695
- inputSchema: { type: "object", properties: { layerId: LAYER_ID4, filterId: FILTER_ID }, required: ["layerId", "filterId"], additionalProperties: false },
18696
- annotations: { title: "Remove a smart filter", ...DESTRUCTIVE5 },
18374
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3, filterId: FILTER_ID }, required: ["layerId", "filterId"], additionalProperties: false },
18375
+ annotations: { title: "Remove a smart filter", ...DESTRUCTIVE4 },
18697
18376
  handler: ({ layerId, filterId }) => {
18698
18377
  const id = smartId(layerId);
18699
18378
  controller.removeSmartFilter(id, filterId);
@@ -18706,11 +18385,11 @@ function createImageSmartObjectTools(controller) {
18706
18385
  description: "Moves one smart filter to a position in the stack (0 = bottom, applied first), as dragging it in the Layers panel. One undo step. Returns the stack in its new order.",
18707
18386
  inputSchema: {
18708
18387
  type: "object",
18709
- properties: { layerId: LAYER_ID4, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
18388
+ properties: { layerId: LAYER_ID3, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
18710
18389
  required: ["layerId", "filterId", "index"],
18711
18390
  additionalProperties: false
18712
18391
  },
18713
- annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT4 },
18392
+ annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT3 },
18714
18393
  handler: ({ layerId, filterId, index }) => {
18715
18394
  const id = smartId(layerId);
18716
18395
  controller.moveSmartFilter(id, filterId, index);
@@ -18723,11 +18402,11 @@ function createImageSmartObjectTools(controller) {
18723
18402
  description: "Layer \u203A Smart Filter \u203A Disable / Enable Smart Filters: switches the whole stack; each filter keeps its own enabled flag. One undo step. Returns the stack.",
18724
18403
  inputSchema: {
18725
18404
  type: "object",
18726
- properties: { layerId: LAYER_ID4, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
18405
+ properties: { layerId: LAYER_ID3, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
18727
18406
  required: ["layerId", "enabled"],
18728
18407
  additionalProperties: false
18729
18408
  },
18730
- annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT4 },
18409
+ annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT3 },
18731
18410
  handler: ({ layerId, enabled }) => {
18732
18411
  const id = smartId(layerId);
18733
18412
  controller.setSmartFiltersEnabled(id, enabled === true);
@@ -18741,7 +18420,7 @@ function createImageSmartObjectTools(controller) {
18741
18420
  inputSchema: {
18742
18421
  type: "object",
18743
18422
  properties: {
18744
- layerId: LAYER_ID4,
18423
+ layerId: LAYER_ID3,
18745
18424
  from: { type: "string", enum: ["reveal-all", "hide-all", "selection", "none", "keep"], description: "What the mask starts from; none removes it; keep only changes the properties below." },
18746
18425
  density: { type: "number", minimum: 0, maximum: 1, description: "How much hidden areas hide, 0..1 (default 1)." },
18747
18426
  feather: { type: "number", minimum: 0, maximum: 1e3, description: "Gaussian softening in px (default 0)." },
@@ -18751,7 +18430,7 @@ function createImageSmartObjectTools(controller) {
18751
18430
  required: ["layerId", "from"],
18752
18431
  additionalProperties: false
18753
18432
  },
18754
- annotations: { title: "Set the smart filter mask", ...WRITE7 },
18433
+ annotations: { title: "Set the smart filter mask", ...WRITE6 },
18755
18434
  handler: (args) => {
18756
18435
  const id = smartId(args.layerId);
18757
18436
  const props = {};
@@ -18764,11 +18443,11 @@ function createImageSmartObjectTools(controller) {
18764
18443
  }
18765
18444
 
18766
18445
  // src/image-editor/shape-tools.ts
18767
- var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18768
- var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18769
- var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18770
- var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18771
- var LAYER_ID5 = { type: "string", description: "Shape layer id from list_layers (type shape) or add_shape_layer." };
18446
+ var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18447
+ var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18448
+ var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18449
+ var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18450
+ var LAYER_ID4 = { type: "string", description: "Shape layer id from list_layers (type shape) or add_shape_layer." };
18772
18451
  var COMPONENT_INDEX = { type: "integer", minimum: 0, description: "Component index from get_shape_layer (0 = bottom component)." };
18773
18452
  var OP = {
18774
18453
  type: "string",
@@ -18790,7 +18469,7 @@ var BOX = {
18790
18469
  height: NUM("Height in pixels."),
18791
18470
  transform: { $ref: "#/$defs/matrix" }
18792
18471
  };
18793
- var DEFS2 = {
18472
+ var DEFS = {
18794
18473
  matrix: MATRIX,
18795
18474
  point: {
18796
18475
  type: "object",
@@ -19017,8 +18696,8 @@ function createImageShapeTools(controller) {
19017
18696
  name: "get_shape_layer",
19018
18697
  title: "Read a shape layer",
19019
18698
  description: "Returns a shape layer\u2019s components bottom to top (index, path operation, the live shape it was drawn as or null, its subpaths with absolute anchors and handles, bounds), the fill rule, fill and stroke paints and settings, the path bounds and the rendered bounds (stroke included). Changes nothing.",
19020
- inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19021
- annotations: { title: "Read a shape layer", ...READ10 },
18699
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18700
+ annotations: { title: "Read a shape layer", ...READ9 },
19022
18701
  handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
19023
18702
  };
19024
18703
  const add2 = {
@@ -19027,7 +18706,7 @@ function createImageShapeTools(controller) {
19027
18706
  description: "Adds a vector shape layer and makes it active: a live shape (rect, ellipse, polygon, star, line), a free path (SVG path data or anchors), or several components combined with path operations. fill defaults to the foreground colour (none for an open path with a stroke); give stroke for an outline. It renders sharp at any size, can be moved and transformed without losing quality, and takes masks, effects, clipping and blend modes like any layer. Goes above the active layer unless placed. One undo step. Returns the layer and the shape.",
19028
18707
  inputSchema: {
19029
18708
  type: "object",
19030
- $defs: DEFS2,
18709
+ $defs: DEFS,
19031
18710
  properties: {
19032
18711
  ...GEOMETRY2,
19033
18712
  components: {
@@ -19049,7 +18728,7 @@ function createImageShapeTools(controller) {
19049
18728
  },
19050
18729
  additionalProperties: false
19051
18730
  },
19052
- annotations: { title: "Add a shape layer", ...WRITE8 },
18731
+ annotations: { title: "Add a shape layer", ...WRITE7 },
19053
18732
  handler: (args) => {
19054
18733
  const init = { ...geometry(args) };
19055
18734
  if (args.components !== void 0) init.components = args.components.map(geometry);
@@ -19067,9 +18746,9 @@ function createImageShapeTools(controller) {
19067
18746
  description: "Changes a shape layer\u2019s fill, stroke or fill rule and renders it again: fill replaces the fill (null removes it); stroke changes only the settings given (null removes the stroke; a new stroke needs width and paint). Geometry is untouched (set_shape_component edits paths). One undo step. Returns the shape.",
19068
18747
  inputSchema: {
19069
18748
  type: "object",
19070
- $defs: DEFS2,
18749
+ $defs: DEFS,
19071
18750
  properties: {
19072
- layerId: LAYER_ID5,
18751
+ layerId: LAYER_ID4,
19073
18752
  fill: { anyOf: [{ $ref: "#/$defs/paint" }, { type: "null", description: "No fill." }], description: "New fill paint, or null for none." },
19074
18753
  stroke: { anyOf: [{ $ref: "#/$defs/stroke" }, { type: "null", description: "No stroke." }], description: "Stroke settings to change, or null to remove the stroke." },
19075
18754
  fillRule: { type: "string", enum: ["nonzero", "evenodd"], description: "Winding rule within a component." }
@@ -19077,7 +18756,7 @@ function createImageShapeTools(controller) {
19077
18756
  required: ["layerId"],
19078
18757
  additionalProperties: false
19079
18758
  },
19080
- annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT5 },
18759
+ annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT4 },
19081
18760
  handler: ({ layerId, fill, stroke, fillRule }) => {
19082
18761
  const id = shapeId(layerId);
19083
18762
  if (fill === void 0 && stroke === void 0 && fillRule === void 0) throw new LayerOperationError("Give fill, stroke or fillRule to change.");
@@ -19090,9 +18769,9 @@ function createImageShapeTools(controller) {
19090
18769
  description: "Changes one component of a shape layer: shape sets its live shape (fields you leave out keep their values when the kind stays the same, e.g. only radii), subpaths replaces its path (which ends the live shape), op changes its path operation. Positions are document pixels. One undo step. Returns the shape.",
19091
18770
  inputSchema: {
19092
18771
  type: "object",
19093
- $defs: DEFS2,
18772
+ $defs: DEFS,
19094
18773
  properties: {
19095
- layerId: LAYER_ID5,
18774
+ layerId: LAYER_ID4,
19096
18775
  componentIndex: COMPONENT_INDEX,
19097
18776
  shape: {
19098
18777
  type: "object",
@@ -19125,7 +18804,7 @@ function createImageShapeTools(controller) {
19125
18804
  required: ["layerId", "componentIndex"],
19126
18805
  additionalProperties: false
19127
18806
  },
19128
- annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT5 },
18807
+ annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT4 },
19129
18808
  handler: ({ layerId, componentIndex, ...rest }) => {
19130
18809
  const id = shapeId(layerId);
19131
18810
  const change = geometry(rest);
@@ -19139,28 +18818,28 @@ function createImageShapeTools(controller) {
19139
18818
  description: "Adds a component to a shape layer and combines it with the components below it by op: combine (union), subtract, intersect or exclude, as Photoshop\u2019s path operations. Goes on top unless index is given. One undo step. Returns the shape.",
19140
18819
  inputSchema: {
19141
18820
  type: "object",
19142
- $defs: DEFS2,
19143
- properties: { layerId: LAYER_ID5, ...GEOMETRY2, op: OP, index: { type: "integer", minimum: 0, description: "Position among the components, 0 = bottom (default the top)." } },
18821
+ $defs: DEFS,
18822
+ properties: { layerId: LAYER_ID4, ...GEOMETRY2, op: OP, index: { type: "integer", minimum: 0, description: "Position among the components, 0 = bottom (default the top)." } },
19144
18823
  required: ["layerId"],
19145
18824
  additionalProperties: false
19146
18825
  },
19147
- annotations: { title: "Add a shape component", ...WRITE8 },
18826
+ annotations: { title: "Add a shape component", ...WRITE7 },
19148
18827
  handler: ({ layerId, index, ...rest }) => controller.addShapeComponent(shapeId(layerId), geometry(rest), index)
19149
18828
  };
19150
18829
  const removeComponent = {
19151
18830
  name: "remove_shape_component",
19152
18831
  title: "Delete a shape component",
19153
18832
  description: "Deletes one component of a shape layer (the last one cannot go: delete the layer instead). One undo step. Returns the shape.",
19154
- inputSchema: { type: "object", properties: { layerId: LAYER_ID5, componentIndex: COMPONENT_INDEX }, required: ["layerId", "componentIndex"], additionalProperties: false },
19155
- annotations: { title: "Delete a shape component", ...DESTRUCTIVE6 },
18833
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4, componentIndex: COMPONENT_INDEX }, required: ["layerId", "componentIndex"], additionalProperties: false },
18834
+ annotations: { title: "Delete a shape component", ...DESTRUCTIVE5 },
19156
18835
  handler: ({ layerId, componentIndex }) => controller.removeShapeComponent(shapeId(layerId), componentIndex)
19157
18836
  };
19158
18837
  const merge = {
19159
18838
  name: "merge_shape_components",
19160
18839
  title: "Merge shape components",
19161
18840
  description: "Merge Shape Components: the area a shape\u2019s components combine to (after their path operations) becomes one plain component; live shapes become paths. The look is unchanged. One undo step. Returns the shape.",
19162
- inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19163
- annotations: { title: "Merge shape components", ...DESTRUCTIVE6 },
18841
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18842
+ annotations: { title: "Merge shape components", ...DESTRUCTIVE5 },
19164
18843
  handler: ({ layerId }) => controller.mergeShapeComponents(shapeId(layerId))
19165
18844
  };
19166
18845
  const layerArg = (v) => {
@@ -19214,7 +18893,7 @@ function createImageShapeTools(controller) {
19214
18893
  title: "Make a path from the selection",
19215
18894
  description: "Make Work Path: traces the selection's outline (where it is at least half selected) into closed B\xE9zier subpaths in document pixels, holes included, within tolerance px. Changes nothing. Returns svg (compact SVG path data) and fillRule evenodd, ready for add_vector_mask, set_vector_mask_path or add_shape_layer (pass the svg as subpaths and fillRule evenodd), plus bounds and the anchor count. Use add_vector_mask from selection to do it in one step.",
19216
18895
  inputSchema: { type: "object", properties: { ...TRACE_PROPS, anchors: { type: "boolean", description: "Also return the subpaths as anchors with handles (default false: svg only)." } }, additionalProperties: false },
19217
- annotations: { title: "Make a path from the selection", ...READ10 },
18896
+ annotations: { title: "Make a path from the selection", ...READ9 },
19218
18897
  handler: (args) => {
19219
18898
  const out = controller.selectionToPath(traceOptions(args));
19220
18899
  const { subpaths, ...rest } = out;
@@ -19227,7 +18906,7 @@ function createImageShapeTools(controller) {
19227
18906
  description: "Make Selection: fills a path (a live shape, free subpaths or SVG path data, or components, in document pixels, as add_shape_layer takes) into a selection, combined with the current one by mode, with feather px and antiAlias. Use it to select along B\xE9zier curves, or to turn a path from selection_to_path or get_vector_mask back into a selection. One undo step. Returns the selection.",
19228
18907
  inputSchema: {
19229
18908
  type: "object",
19230
- $defs: DEFS2,
18909
+ $defs: DEFS,
19231
18910
  properties: {
19232
18911
  pathId: { ...PATH_ID, description: "A document path from list_paths, instead of shape / subpaths / components." },
19233
18912
  ...PATH_PROPS,
@@ -19237,7 +18916,7 @@ function createImageShapeTools(controller) {
19237
18916
  },
19238
18917
  additionalProperties: false
19239
18918
  },
19240
- annotations: { title: "Make a selection from a path", ...WRITE8 },
18919
+ annotations: { title: "Make a selection from a path", ...WRITE7 },
19241
18920
  handler: (args) => {
19242
18921
  const mode = args.mode;
19243
18922
  controller.pathToSelection(fromPathId(args) ?? pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
@@ -19250,7 +18929,7 @@ function createImageShapeTools(controller) {
19250
18929
  title: "Read a vector mask",
19251
18930
  description: "Reads a layer's vector mask: enabled, linked, inverted, fill rule, density, feather, the bounds of its path and its components (op, live shape, subpaths in document pixels). Use it before set_vector_mask_path to edit the path. Returns null when the layer has none.",
19252
18931
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19253
- annotations: { title: "Read a vector mask", ...READ10 },
18932
+ annotations: { title: "Read a vector mask", ...READ9 },
19254
18933
  handler: ({ layerId }) => ({ vectorMask: controller.getVectorMask(layerArg(layerId)) })
19255
18934
  };
19256
18935
  const addVectorMask = {
@@ -19259,7 +18938,7 @@ function createImageShapeTools(controller) {
19259
18938
  description: "Layer \u203A Vector Mask: a path that reveals the layer inside it and stays sharp at any size, on top of any raster mask (both apply). from path takes a live shape, free subpaths or components like add_shape_layer; from selection traces the current selection (within tolerance px); reveal-all and hide-all start with an empty path. Use it for hard-edged geometric or traced cutouts that must stay editable; use add_layer_mask for soft or painted ones. A linked vector mask moves and transforms with the layer. Replaces an existing vector mask. One undo step. Returns the vector mask.",
19260
18939
  inputSchema: {
19261
18940
  type: "object",
19262
- $defs: DEFS2,
18941
+ $defs: DEFS,
19263
18942
  properties: {
19264
18943
  layerId: LAYER,
19265
18944
  from: { type: "string", enum: ["path", "selection", "reveal-all", "hide-all"], description: "path (default when a shape, subpaths, components or pathId are given), selection (trace the current selection), reveal-all or hide-all (an empty path)." },
@@ -19270,7 +18949,7 @@ function createImageShapeTools(controller) {
19270
18949
  required: ["layerId"],
19271
18950
  additionalProperties: false
19272
18951
  },
19273
- annotations: { title: "Add a vector mask", ...WRITE8 },
18952
+ annotations: { title: "Add a vector mask", ...WRITE7 },
19274
18953
  handler: (args) => {
19275
18954
  const id = layerArg(args.layerId);
19276
18955
  const spec = fromPathId(args) ?? pathSpec(args);
@@ -19285,8 +18964,8 @@ function createImageShapeTools(controller) {
19285
18964
  name: "set_vector_mask_path",
19286
18965
  title: "Replace a vector mask path",
19287
18966
  description: "Replaces the path of a layer's vector mask (shape, subpaths or components, document pixels); enabled, linked, inverted, density and feather are kept. Read the current path with get_vector_mask first to change part of it. One undo step. Returns the vector mask.",
19288
- inputSchema: { type: "object", $defs: DEFS2, properties: { layerId: LAYER, ...PATH_PROPS }, required: ["layerId"], additionalProperties: false },
19289
- annotations: { title: "Replace a vector mask path", ...WRITE_IDEMPOTENT5 },
18967
+ inputSchema: { type: "object", $defs: DEFS, properties: { layerId: LAYER, ...PATH_PROPS }, required: ["layerId"], additionalProperties: false },
18968
+ annotations: { title: "Replace a vector mask path", ...WRITE_IDEMPOTENT4 },
19290
18969
  handler: (args) => {
19291
18970
  const id = layerArg(args.layerId);
19292
18971
  controller.setVectorMaskPath(id, pathSpec(args));
@@ -19310,7 +18989,7 @@ function createImageShapeTools(controller) {
19310
18989
  required: ["layerId"],
19311
18990
  additionalProperties: false
19312
18991
  },
19313
- annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT5 },
18992
+ annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT4 },
19314
18993
  handler: ({ layerId, ...props }) => {
19315
18994
  const id = layerArg(layerId);
19316
18995
  controller.setVectorMaskProps(id, props);
@@ -19336,7 +19015,7 @@ function createImageShapeTools(controller) {
19336
19015
  required: ["layerId", "component", "subpath", "segment", "mode"],
19337
19016
  additionalProperties: false
19338
19017
  },
19339
- annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT5 },
19018
+ annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT4 },
19340
19019
  handler: ({ layerId, component, subpath, segment, mode, radius, inner, outer }) => {
19341
19020
  const id = layerArg(layerId);
19342
19021
  const vectorMask = controller.setVectorMaskEdge(
@@ -19353,7 +19032,7 @@ function createImageShapeTools(controller) {
19353
19032
  title: "Rasterize a vector mask",
19354
19033
  description: "Layer \u203A Rasterize \u203A Vector Mask: multiplies the path (with its density and feather) into the layer's raster mask, adding one if needed, and removes the vector mask, so the mask can be painted. The path can no longer be edited (undo_image brings it back). One undo step. Returns the layer's raster mask summary.",
19355
19034
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19356
- annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE6 },
19035
+ annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE5 },
19357
19036
  handler: ({ layerId }) => {
19358
19037
  const id = layerArg(layerId);
19359
19038
  const mask = controller.rasterizeVectorMask(id);
@@ -19365,7 +19044,7 @@ function createImageShapeTools(controller) {
19365
19044
  title: "Delete a vector mask",
19366
19045
  description: "Deletes a layer's vector mask without applying it (the raster mask, if any, stays). Disable it instead with set_vector_mask_properties enabled false to keep it. One undo step. Returns the layer id.",
19367
19046
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19368
- annotations: { title: "Delete a vector mask", ...DESTRUCTIVE6 },
19047
+ annotations: { title: "Delete a vector mask", ...DESTRUCTIVE5 },
19369
19048
  handler: ({ layerId }) => {
19370
19049
  const id = layerArg(layerId);
19371
19050
  controller.removeVectorMask(id);
@@ -19377,15 +19056,15 @@ function createImageShapeTools(controller) {
19377
19056
  title: "List document paths",
19378
19057
  description: "Paths panel: the document's saved paths and its Work Path (paths kept with the document, on no layer), each with id, name, work (true for the Work Path, which the next make_work_path replaces), fill rule, anchor count and bounds, and which is active. Use the ids with path_to_selection, add_vector_mask, fill_path, stroke_path and the other path tools.",
19379
19058
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
19380
- annotations: { title: "List document paths", ...READ10 },
19059
+ annotations: { title: "List document paths", ...READ9 },
19381
19060
  handler: () => ({ paths: controller.getPaths().map((p) => pathSummary(p.id)), activePathId: controller.getState().activePathId ?? null })
19382
19061
  };
19383
- const getPath2 = {
19062
+ const getPath = {
19384
19063
  name: "get_path",
19385
19064
  title: "Read a document path",
19386
19065
  description: "Reads a document path: its summary, svg (compact SVG path data) and components (op, subpaths of anchors with handles, in document pixels), ready to edit and pass back to set_path_geometry.",
19387
19066
  inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
19388
- annotations: { title: "Read a document path", ...READ10 },
19067
+ annotations: { title: "Read a document path", ...READ9 },
19389
19068
  handler: ({ pathId }) => {
19390
19069
  const p = controller.getPath(String(pathId));
19391
19070
  if (!p) throw new Error(`No path "${String(pathId)}". Call list_paths for ids.`);
@@ -19397,7 +19076,7 @@ function createImageShapeTools(controller) {
19397
19076
  title: "Make a work path from the selection",
19398
19077
  description: "Paths \u203A Make Work Path: traces the selection's outline (within tolerance px) into the Work Path, replacing the last Work Path unless it was saved (rename_path saves it). Use it to keep a selection as an editable, resolution-independent outline. One undo step. Returns the path.",
19399
19078
  inputSchema: { type: "object", properties: { ...TRACE_PROPS }, additionalProperties: false },
19400
- annotations: { title: "Make a work path from the selection", ...WRITE8 },
19079
+ annotations: { title: "Make a work path from the selection", ...WRITE7 },
19401
19080
  handler: (args) => ({ path: pathSummary(controller.makeWorkPath(traceOptions(args)).id) })
19402
19081
  };
19403
19082
  const addPath = {
@@ -19406,11 +19085,11 @@ function createImageShapeTools(controller) {
19406
19085
  description: "Adds a saved document path from a live shape, free subpaths or SVG path data, or components (document pixels), as add_shape_layer takes them. One undo step. Returns the path.",
19407
19086
  inputSchema: {
19408
19087
  type: "object",
19409
- $defs: DEFS2,
19088
+ $defs: DEFS,
19410
19089
  properties: { name: { type: "string", description: 'The path name (default "Path n").' }, ...PATH_PROPS },
19411
19090
  additionalProperties: false
19412
19091
  },
19413
- annotations: { title: "Add a document path", ...WRITE8 },
19092
+ annotations: { title: "Add a document path", ...WRITE7 },
19414
19093
  handler: (args) => {
19415
19094
  const spec = pathSpec(args);
19416
19095
  if (!spec.components?.length && spec.shape === void 0 && spec.subpaths === void 0) throw new Error("Give the path as shape, subpaths or components.");
@@ -19421,8 +19100,8 @@ function createImageShapeTools(controller) {
19421
19100
  name: "set_path_geometry",
19422
19101
  title: "Replace a document path",
19423
19102
  description: "Replaces a document path's geometry (shape, subpaths or components, document pixels); its name is kept. Read it with get_path first to change part of it. One undo step. Returns the path.",
19424
- inputSchema: { type: "object", $defs: DEFS2, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
19425
- annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT5 },
19103
+ inputSchema: { type: "object", $defs: DEFS, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
19104
+ annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT4 },
19426
19105
  handler: (args) => ({ path: pathSummary(controller.setPathGeometry(String(args.pathId), pathSpec(args)).id) })
19427
19106
  };
19428
19107
  const renamePath = {
@@ -19430,7 +19109,7 @@ function createImageShapeTools(controller) {
19430
19109
  title: "Rename or save a path",
19431
19110
  description: "Renames a document path. Renaming the Work Path saves it (Paths \u203A Save Path), so make_work_path no longer replaces it. One undo step. Returns the path.",
19432
19111
  inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", minLength: 1, description: "The new name." } }, required: ["pathId", "name"], additionalProperties: false },
19433
- annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT5 },
19112
+ annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT4 },
19434
19113
  handler: ({ pathId, name }) => ({ path: pathSummary(controller.renamePath(String(pathId), String(name)).id) })
19435
19114
  };
19436
19115
  const duplicatePath = {
@@ -19438,7 +19117,7 @@ function createImageShapeTools(controller) {
19438
19117
  title: "Duplicate a path",
19439
19118
  description: 'Duplicates a document path as a saved path (default name "<name> copy"). One undo step. Returns the new path.',
19440
19119
  inputSchema: { type: "object", properties: { pathId: PATH_ID, name: { type: "string", description: "The copy's name." } }, required: ["pathId"], additionalProperties: false },
19441
- annotations: { title: "Duplicate a path", ...WRITE8 },
19120
+ annotations: { title: "Duplicate a path", ...WRITE7 },
19442
19121
  handler: ({ pathId, name }) => ({ path: pathSummary(controller.duplicatePath(String(pathId), name).id) })
19443
19122
  };
19444
19123
  const deletePath = {
@@ -19446,7 +19125,7 @@ function createImageShapeTools(controller) {
19446
19125
  title: "Delete a path",
19447
19126
  description: "Deletes a document path (undo_image brings it back). Returns the remaining paths.",
19448
19127
  inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
19449
- annotations: { title: "Delete a path", ...DESTRUCTIVE6 },
19128
+ annotations: { title: "Delete a path", ...DESTRUCTIVE5 },
19450
19129
  handler: ({ pathId }) => {
19451
19130
  controller.deletePath(String(pathId));
19452
19131
  return { paths: controller.getPaths().map((p) => pathSummary(p.id)) };
@@ -19462,7 +19141,7 @@ function createImageShapeTools(controller) {
19462
19141
  title: "Fill a path",
19463
19142
  description: "Paths \u203A Fill Path: fills the area a document path encloses on a pixel layer with a colour. The selection is not changed. One undo step. Returns what was painted.",
19464
19143
  inputSchema: { type: "object", properties: { pathId: PATH_ID, ...PAINT_PROPS }, required: ["pathId"], additionalProperties: false },
19465
- annotations: { title: "Fill a path", ...WRITE8 },
19144
+ annotations: { title: "Fill a path", ...WRITE7 },
19466
19145
  handler: (args) => controller.fillPath(String(args.pathId), { layerId: args.layerId, color: args.color, opacity: args.opacity })
19467
19146
  };
19468
19147
  const strokePath = {
@@ -19475,7 +19154,7 @@ function createImageShapeTools(controller) {
19475
19154
  required: ["pathId", "width"],
19476
19155
  additionalProperties: false
19477
19156
  },
19478
- annotations: { title: "Stroke a path", ...WRITE8 },
19157
+ annotations: { title: "Stroke a path", ...WRITE7 },
19479
19158
  handler: (args) => controller.strokePath(String(args.pathId), { width: args.width, layerId: args.layerId, color: args.color, opacity: args.opacity })
19480
19159
  };
19481
19160
  return [
@@ -19496,7 +19175,7 @@ function createImageShapeTools(controller) {
19496
19175
  selectionToPath,
19497
19176
  pathToSelection2,
19498
19177
  listPaths,
19499
- getPath2,
19178
+ getPath,
19500
19179
  makeWorkPath,
19501
19180
  addPath,
19502
19181
  setPathGeometry,
@@ -19509,11 +19188,11 @@ function createImageShapeTools(controller) {
19509
19188
  }
19510
19189
 
19511
19190
  // src/image-editor/type-tools.ts
19512
- var READ11 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19513
- var WRITE9 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
19514
- var WRITE_IDEMPOTENT6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19515
- var DESTRUCTIVE7 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
19516
- var LAYER_ID6 = { type: "string", description: "Type layer id from list_layers (type type) or add_text_layer." };
19191
+ var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19192
+ var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
19193
+ var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19194
+ var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
19195
+ var LAYER_ID5 = { type: "string", description: "Type layer id from list_layers (type type) or add_text_layer." };
19517
19196
  var START = { type: "integer", minimum: 0, description: "Start of the range in UTF-16 code units, as get_text_layer counts them (default 0)." };
19518
19197
  var END = { type: "integer", minimum: 0, description: "End of the range, exclusive (default the end of the text)." };
19519
19198
  var STYLE = {
@@ -19566,15 +19245,15 @@ function createImageTypeTools(controller) {
19566
19245
  title: "List fonts",
19567
19246
  description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
19568
19247
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
19569
- annotations: { title: "List fonts", ...READ11 },
19248
+ annotations: { title: "List fonts", ...READ10 },
19570
19249
  handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
19571
19250
  };
19572
19251
  const get = {
19573
19252
  name: "get_text_layer",
19574
19253
  title: "Read a type layer",
19575
19254
  description: "Returns a type layer\u2019s text, its character runs and paragraphs as [start, end) ranges in UTF-16 code units with their styles, the frame (point text, or a paragraph box with its size), the orientation (horizontal or vertical), the text-to-document transform, the laid-out lines (range, baseline, width), the rendered bounds, missing fonts and whether the pixels are live or stored from a file. Call before editing text you did not write, to get the ranges. Changes nothing.",
19576
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6 }, required: ["layerId"], additionalProperties: false },
19577
- annotations: { title: "Read a type layer", ...READ11 },
19255
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19256
+ annotations: { title: "Read a type layer", ...READ10 },
19578
19257
  handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
19579
19258
  };
19580
19259
  const add2 = {
@@ -19609,7 +19288,7 @@ function createImageTypeTools(controller) {
19609
19288
  required: ["text", "x", "y"],
19610
19289
  additionalProperties: false
19611
19290
  },
19612
- annotations: { title: "Add a type layer", ...WRITE9 },
19291
+ annotations: { title: "Add a type layer", ...WRITE8 },
19613
19292
  handler: (args) => {
19614
19293
  const init = pick2(args, ["text", "x", "y", "box", "style", "paragraph", "orientation", "rotation", "name", "opacity", "blend", "aboveId", "belowId", "parentId", "index"]);
19615
19294
  if (init.blend !== void 0) init.blend = init.blend;
@@ -19621,16 +19300,16 @@ function createImageTypeTools(controller) {
19621
19300
  name: "set_text",
19622
19301
  title: "Edit text",
19623
19302
  description: "Replaces the text in [start, end) (default all of it) with text; inserted text takes the style of the character at start. Use start = end to insert. Returns the text layer with its new runs.",
19624
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6, text: { type: "string", description: "Replacement text (\\n starts a paragraph; empty deletes the range)." }, start: START, end: END }, required: ["layerId", "text"], additionalProperties: false },
19625
- annotations: { title: "Edit text", ...WRITE9 },
19303
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, text: { type: "string", description: "Replacement text (\\n starts a paragraph; empty deletes the range)." }, start: START, end: END }, required: ["layerId", "text"], additionalProperties: false },
19304
+ annotations: { title: "Edit text", ...WRITE8 },
19626
19305
  handler: (args) => controller.setText(typeId(args.layerId), args.text, range(args))
19627
19306
  };
19628
19307
  const setStyle = {
19629
19308
  name: "set_text_style",
19630
19309
  title: "Style a range of text",
19631
19310
  description: "Sets character style fields (font, weight, italic, size, colour, tracking, leading, baseline shift, underline, strike-through) over [start, end) of a type layer (default all of it); fields not given keep their values per run. Returns the text layer with its runs and missingFonts.",
19632
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6, start: START, end: END, ...STYLE }, required: ["layerId"], additionalProperties: false },
19633
- annotations: { title: "Style a range of text", ...WRITE_IDEMPOTENT6 },
19311
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...STYLE }, required: ["layerId"], additionalProperties: false },
19312
+ annotations: { title: "Style a range of text", ...WRITE_IDEMPOTENT5 },
19634
19313
  handler: (args) => {
19635
19314
  const style = pick2(args, Object.keys(STYLE));
19636
19315
  if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one style field: ${Object.keys(STYLE).join(", ")}.`);
@@ -19641,8 +19320,8 @@ function createImageTypeTools(controller) {
19641
19320
  name: "set_paragraph_style",
19642
19321
  title: "Style paragraphs",
19643
19322
  description: "Sets paragraph fields (alignment, auto leading, indents, spacing) on every paragraph that [start, end) touches (default all). Returns the text layer.",
19644
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6, start: START, end: END, ...PARAGRAPH }, required: ["layerId"], additionalProperties: false },
19645
- annotations: { title: "Style paragraphs", ...WRITE_IDEMPOTENT6 },
19323
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...PARAGRAPH }, required: ["layerId"], additionalProperties: false },
19324
+ annotations: { title: "Style paragraphs", ...WRITE_IDEMPOTENT5 },
19646
19325
  handler: (args) => {
19647
19326
  const style = pick2(args, Object.keys(PARAGRAPH));
19648
19327
  if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one paragraph field: ${Object.keys(PARAGRAPH).join(", ")}.`);
@@ -19656,7 +19335,7 @@ function createImageTypeTools(controller) {
19656
19335
  inputSchema: {
19657
19336
  type: "object",
19658
19337
  properties: {
19659
- layerId: LAYER_ID6,
19338
+ layerId: LAYER_ID5,
19660
19339
  kind: { type: "string", enum: ["point", "box"], description: "point or box." },
19661
19340
  width: { type: "number", minimum: 1, description: "Box width in pixels (kind box)." },
19662
19341
  height: { type: "number", minimum: 1, description: "Box height in pixels (kind box)." }
@@ -19664,7 +19343,7 @@ function createImageTypeTools(controller) {
19664
19343
  required: ["layerId", "kind"],
19665
19344
  additionalProperties: false
19666
19345
  },
19667
- annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT6 },
19346
+ annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT5 },
19668
19347
  handler: ({ layerId, kind, width, height }) => {
19669
19348
  const id = typeId(layerId);
19670
19349
  if (kind === "box" && (width === void 0 || height === void 0)) throw new LayerOperationError("kind box needs width and height in pixels.");
@@ -19675,16 +19354,16 @@ function createImageTypeTools(controller) {
19675
19354
  name: "set_text_orientation",
19676
19355
  title: "Horizontal or vertical type",
19677
19356
  description: "Type \u203A Orientation: sets a type layer horizontal (lines left to right) or vertical (columns top to bottom, right to left). The text, styles, frame and origin stay. One undo step. Returns the text layer with its orientation and new lines (columns).",
19678
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6, orientation: { ...ORIENTATION, description: "horizontal or vertical." } }, required: ["layerId", "orientation"], additionalProperties: false },
19679
- annotations: { title: "Horizontal or vertical type", ...WRITE_IDEMPOTENT6 },
19357
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, orientation: { ...ORIENTATION, description: "horizontal or vertical." } }, required: ["layerId", "orientation"], additionalProperties: false },
19358
+ annotations: { title: "Horizontal or vertical type", ...WRITE_IDEMPOTENT5 },
19680
19359
  handler: ({ layerId, orientation }) => controller.setTextOrientation(typeId(layerId), orientation)
19681
19360
  };
19682
19361
  const toShape = {
19683
19362
  name: "convert_text_to_shape",
19684
19363
  title: "Convert text to a shape",
19685
19364
  description: "Type \u203A Convert to Shape: the text\u2019s glyph outlines become a shape layer (same id, name, mask, effects, opacity, blend) that can be edited with the shape tools; the text is no longer editable. Needs a font shaper that gives outlines (the browser\u2019s canvas cannot). The fill is the first run\u2019s colour. One undo step. Returns the layer and warnings.",
19686
- inputSchema: { type: "object", properties: { layerId: LAYER_ID6 }, required: ["layerId"], additionalProperties: false },
19687
- annotations: { title: "Convert text to a shape", ...DESTRUCTIVE7 },
19365
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19366
+ annotations: { title: "Convert text to a shape", ...DESTRUCTIVE6 },
19688
19367
  handler: ({ layerId }) => {
19689
19368
  const { layerId: id, warnings } = controller.convertTextToShape(typeId(layerId));
19690
19369
  return { layer: layerSummary(id), shape: controller.getShapeLayer(id), warnings };
@@ -19718,7 +19397,7 @@ function createImageTypeTools(controller) {
19718
19397
  required: ["text", "x", "y"],
19719
19398
  additionalProperties: false
19720
19399
  },
19721
- annotations: { title: "Select the shape of text", ...WRITE9 },
19400
+ annotations: { title: "Select the shape of text", ...WRITE8 },
19722
19401
  handler: (args) => {
19723
19402
  const init = pick2(args, ["text", "x", "y", "orientation", "box", "style", "paragraph", "rotation", "mode", "feather", "antiAlias"]);
19724
19403
  controller.selectTextShape(init);
@@ -20231,12 +19910,12 @@ var SelectAndMaskSession = class {
20231
19910
  this.recompute();
20232
19911
  }
20233
19912
  rescale() {
20234
- const px2 = this.pixels;
20235
- if (!px2) return;
20236
- const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(px2.width, px2.height));
20237
- const w = Math.max(1, Math.round(px2.width * s));
20238
- const h = Math.max(1, Math.round(px2.height * s));
20239
- this.previewPixels = scalePixels(px2, w, h);
19913
+ const px = this.pixels;
19914
+ if (!px) return;
19915
+ const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(px.width, px.height));
19916
+ const w = Math.max(1, Math.round(px.width * s));
19917
+ const h = Math.max(1, Math.round(px.height * s));
19918
+ this.previewPixels = scalePixels(px, w, h);
20240
19919
  this.belowPreview = this.below ? scalePixels(this.below, w, h) : null;
20241
19920
  this.baseMask = this.base?.bounds ? s === 1 ? this.base : resizeSelection(this.base, w, h) : null;
20242
19921
  }
@@ -20245,8 +19924,8 @@ var SelectAndMaskSession = class {
20245
19924
  * the page, or in the worker, where one job runs at a time and the newest state follows it.
20246
19925
  */
20247
19926
  recompute() {
20248
- const px2 = this.previewPixels;
20249
- if (!px2) return;
19927
+ const px = this.previewPixels;
19928
+ if (!px) return;
20250
19929
  this.note = this.settingsValue.refineMode === "object" ? "Object aware refinement asks the segmentation model on OK; the preview refines by colour." : null;
20251
19930
  if (this.controller.hasSelectionWorker) {
20252
19931
  void this.recomputeInWorker();
@@ -20255,8 +19934,8 @@ var SelectAndMaskSession = class {
20255
19934
  const { scale } = this.previewSize;
20256
19935
  const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
20257
19936
  try {
20258
- const { selection, refineBrush } = applyRefineEdits(px2, this.baseMask, edits, px2.width, px2.height);
20259
- this.previewMask = selection?.bounds ? refineSelection(px2, selection, scaleParams(this.settingsValue.params, scale), refineBrush) : null;
19937
+ const { selection, refineBrush } = applyRefineEdits(px, this.baseMask, edits, px.width, px.height);
19938
+ this.previewMask = selection?.bounds ? refineSelection(px, selection, scaleParams(this.settingsValue.params, scale), refineBrush) : null;
20260
19939
  this.error = null;
20261
19940
  } catch (err) {
20262
19941
  this.previewMask = null;
@@ -20272,13 +19951,13 @@ var SelectAndMaskSession = class {
20272
19951
  this.computing = true;
20273
19952
  do {
20274
19953
  this.dirty = false;
20275
- const px2 = this.previewPixels;
19954
+ const px = this.previewPixels;
20276
19955
  const { scale } = this.previewSize;
20277
19956
  const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
20278
19957
  try {
20279
19958
  const { mask } = await this.controller.runSelectionJob(
20280
19959
  { op: "refine-preview", base: this.baseMask ? serializeMask(this.baseMask) : null, edits, params: scaleParams(this.settingsValue.params, scale) },
20281
- px2
19960
+ px
20282
19961
  );
20283
19962
  this.previewMask = mask.bounds ? mask : null;
20284
19963
  this.error = null;
@@ -20306,9 +19985,9 @@ var SelectAndMaskSession = class {
20306
19985
  }
20307
19986
  /** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
20308
19987
  render() {
20309
- const px2 = this.previewPixels;
20310
- if (!px2) return new Uint8ClampedArray(0);
20311
- const { width: w, height: h } = px2;
19988
+ const px = this.previewPixels;
19989
+ if (!px) return new Uint8ClampedArray(0);
19990
+ const { width: w, height: h } = px;
20312
19991
  const n = w * h;
20313
19992
  const s = this.settingsValue;
20314
19993
  const mask = (s.showOriginal ? this.baseMask : this.previewMask) ?? createSelectionMask(w, h);
@@ -20330,9 +20009,9 @@ var SelectAndMaskSession = class {
20330
20009
  for (let i = 0; i < n; i++) {
20331
20010
  const a = m[i] / 255;
20332
20011
  const p = i * 4;
20333
- const r = px2.data[p];
20334
- const g = px2.data[p + 1];
20335
- const b = px2.data[p + 2];
20012
+ const r = px.data[p];
20013
+ const g = px.data[p + 1];
20014
+ const b = px.data[p + 2];
20336
20015
  let o;
20337
20016
  const x = i % w;
20338
20017
  const y = (i - x) / w;
@@ -20559,8 +20238,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
20559
20238
  const count = bw * bh;
20560
20239
  for (let py = by; py < by + bh; py++) {
20561
20240
  const rowOffset = py * width;
20562
- for (let px2 = bx; px2 < bx + bw; px2++) {
20563
- const idx = (rowOffset + px2) * 4;
20241
+ for (let px = bx; px < bx + bw; px++) {
20242
+ const idx = (rowOffset + px) * 4;
20564
20243
  rSum += data[idx];
20565
20244
  gSum += data[idx + 1];
20566
20245
  bSum += data[idx + 2];
@@ -20573,8 +20252,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
20573
20252
  const aAvg = Math.round(aSum / count);
20574
20253
  for (let py = by; py < by + bh; py++) {
20575
20254
  const rowOffset = py * width;
20576
- for (let px2 = bx; px2 < bx + bw; px2++) {
20577
- const idx = (rowOffset + px2) * 4;
20255
+ for (let px = bx; px < bx + bw; px++) {
20256
+ const idx = (rowOffset + px) * 4;
20578
20257
  data[idx] = rAvg;
20579
20258
  data[idx + 1] = gAvg;
20580
20259
  data[idx + 2] = bAvg;
@@ -21074,179 +20753,6 @@ function layerPanels(layer, options = {}) {
21074
20753
  return panels;
21075
20754
  }
21076
20755
 
21077
- // src/image-editor/layers/effects-ui.ts
21078
- function layerEffectsPanel(layer) {
21079
- const empty = { readOnly: true, enabled: true, scale: 1, rows: [] };
21080
- if (!layer) return { ...empty, available: false, reason: "Select a layer to add a layer style." };
21081
- if (layer.type === "adjustment") return { ...empty, available: false, reason: "Adjustment layers cannot have a layer style." };
21082
- const fx = layer.effects;
21083
- const readOnly = Boolean(layer.locks?.all);
21084
- return {
21085
- available: true,
21086
- readOnly,
21087
- reason: readOnly ? "The layer is locked; unlock it to change its layer style." : void 0,
21088
- enabled: fx?.enabled ?? true,
21089
- scale: fx?.scale ?? 1,
21090
- rows: (fx?.items ?? []).map((e) => ({ id: e.id, kind: e.kind, label: layerEffectLabel(e.kind), enabled: e.enabled }))
21091
- };
21092
- }
21093
- function layerEffectsBadge(layer) {
21094
- if (!layer.effects?.items.length) return null;
21095
- return hasActiveEffects(layer.effects) ? "on" : "off";
21096
- }
21097
- var LAYER_EFFECT_MENU = LAYER_EFFECT_KINDS.map((kind) => ({ kind, label: layerEffectLabel(kind) }));
21098
- var BLENDS = BLEND_MODES.filter((m) => m.id !== "pigment").map((m) => ({ value: m.id, label: m.label }));
21099
- var opt = (...pairs) => pairs.map(([value, label]) => ({ value, label }));
21100
- function patternOptions(patterns) {
21101
- return [...patterns.map((p) => ({ value: p.id, label: p.name || p.id })), ...builtinPatternIds().map((id) => ({ value: id, label: builtinPattern(id).name }))];
21102
- }
21103
- function getPath(o, path) {
21104
- let v = o;
21105
- for (const p of path.split(".")) {
21106
- if (v === null || v === void 0) return void 0;
21107
- if (Array.isArray(v)) v = p === "last" ? v[v.length - 1] : v[Number(p)];
21108
- else v = v[p];
21109
- }
21110
- return v;
21111
- }
21112
- function setPath(o, parts, value) {
21113
- if (!parts.length) return value;
21114
- const [p, ...rest] = parts;
21115
- if (Array.isArray(o)) {
21116
- const i = p === "last" ? o.length - 1 : Number(p);
21117
- const out = [...o];
21118
- out[i] = setPath(o[i], rest, value);
21119
- return out;
21120
- }
21121
- const r = o ?? {};
21122
- return { ...r, [p]: setPath(r[p], rest, value) };
21123
- }
21124
- function fillControls(f, allowPattern, patterns) {
21125
- const types = allowPattern ? opt(["color", "Color"], ["gradient", "Gradient"], ["pattern", "Pattern"]) : opt(["color", "Color"], ["gradient", "Gradient"]);
21126
- const out = [{ key: "fill.type", label: "Fill", type: "select", value: f.type, options: types }];
21127
- if (f.type === "color") out.push({ key: "fill.color", label: "Color", type: "color", value: f.color });
21128
- else if (f.type === "gradient") out.push(...gradientControls("fill.gradient", f.gradient));
21129
- else {
21130
- out.push(
21131
- { key: "fill.patternId", label: "Pattern", type: "select", value: f.patternId, options: patternOptions(patterns) },
21132
- { key: "fill.scale", label: "Scale", type: "range", min: 0.01, max: 10, step: 0.01, value: f.scale, percent: true, unit: "%" }
21133
- );
21134
- }
21135
- return out;
21136
- }
21137
- function gradientControls(prefix, g) {
21138
- return [
21139
- { key: `${prefix}.stops.0.color`, label: "Start colour", type: "color", value: g.stops[0]?.color ?? "#000000" },
21140
- { key: `${prefix}.stops.last.color`, label: "End colour", type: "color", value: g.stops[g.stops.length - 1]?.color ?? "#ffffff" },
21141
- { key: `${prefix}.style`, label: "Style", type: "select", value: g.style, options: opt(["linear", "Linear"], ["radial", "Radial"], ["angle", "Angle"], ["reflected", "Reflected"], ["diamond", "Diamond"]) },
21142
- { key: `${prefix}.angle`, label: "Angle", type: "range", min: -180, max: 180, step: 1, value: g.angle, unit: "\xB0" },
21143
- { key: `${prefix}.scale`, label: "Scale", type: "range", min: 0.1, max: 1.5, step: 0.01, value: g.scale, percent: true, unit: "%" },
21144
- { key: `${prefix}.reverse`, label: "Reverse", type: "checkbox", value: g.reverse },
21145
- { key: `${prefix}.align`, label: "Align with layer", type: "checkbox", value: g.align }
21146
- ];
21147
- }
21148
- var px = (key2, label, value, max = 250) => ({ key: key2, label, type: "range", min: 0, max, step: 1, value, unit: "px" });
21149
- var pct = (key2, label, value, min = 0, max = 1) => ({ key: key2, label, type: "range", min, max, step: 0.01, value, percent: true, unit: "%" });
21150
- var deg = (key2, label, value, min = -180, max = 180) => ({ key: key2, label, type: "range", min, max, step: 1, value, unit: "\xB0" });
21151
- function layerEffectControls(e, patterns = []) {
21152
- const blended = e.kind === "bevel-emboss" ? [] : [
21153
- { key: "blend", label: "Blend mode", type: "select", value: e.blend, options: BLENDS },
21154
- pct("opacity", "Opacity", e.opacity)
21155
- ];
21156
- switch (e.kind) {
21157
- case "drop-shadow":
21158
- case "inner-shadow":
21159
- return [
21160
- ...blended,
21161
- { key: "color", label: "Color", type: "color", value: e.color },
21162
- { key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
21163
- deg("angle", "Angle", e.angle),
21164
- px("distance", "Distance", e.distance, 500),
21165
- e.kind === "drop-shadow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
21166
- px("size", "Size", e.size),
21167
- pct("noise", "Noise", e.noise),
21168
- ...e.kind === "drop-shadow" ? [{ key: "knocksOut", label: "Layer knocks out shadow", type: "checkbox", value: e.knocksOut }] : []
21169
- ];
21170
- case "outer-glow":
21171
- case "inner-glow":
21172
- return [
21173
- ...blended,
21174
- ...fillControls(e.fill, false, patterns),
21175
- { key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["softer", "Softer"], ["precise", "Precise"]) },
21176
- ...e.kind === "inner-glow" ? [{ key: "source", label: "Source", type: "select", value: e.source, options: opt(["edge", "Edge"], ["center", "Center"]) }] : [],
21177
- e.kind === "outer-glow" ? pct("spread", "Spread", e.spread) : pct("choke", "Choke", e.choke),
21178
- px("size", "Size", e.size),
21179
- pct("range", "Range", e.range, 0.01, 1),
21180
- pct("noise", "Noise", e.noise)
21181
- ];
21182
- case "bevel-emboss":
21183
- return [
21184
- { key: "style", label: "Style", type: "select", value: e.style, options: opt(["inner-bevel", "Inner Bevel"], ["outer-bevel", "Outer Bevel"], ["emboss", "Emboss"], ["pillow-emboss", "Pillow Emboss"], ["stroke-emboss", "Stroke Emboss"]) },
21185
- { key: "technique", label: "Technique", type: "select", value: e.technique, options: opt(["smooth", "Smooth"], ["chisel-hard", "Chisel Hard"], ["chisel-soft", "Chisel Soft"]) },
21186
- pct("depth", "Depth", e.depth, 0, 10),
21187
- { key: "direction", label: "Direction", type: "select", value: e.direction, options: opt(["up", "Up"], ["down", "Down"]) },
21188
- px("size", "Size", e.size),
21189
- px("soften", "Soften", e.soften, 16),
21190
- { key: "useGlobalLight", label: "Use global light", type: "checkbox", value: e.useGlobalLight },
21191
- deg("angle", "Angle", e.angle),
21192
- deg("altitude", "Altitude", e.altitude, 0, 90),
21193
- { key: "highlightColor", label: "Highlight", type: "color", value: e.highlightColor },
21194
- { key: "highlightBlend", label: "Highlight mode", type: "select", value: e.highlightBlend, options: BLENDS },
21195
- pct("highlightOpacity", "Highlight opacity", e.highlightOpacity),
21196
- { key: "shadowColor", label: "Shadow", type: "color", value: e.shadowColor },
21197
- { key: "shadowBlend", label: "Shadow mode", type: "select", value: e.shadowBlend, options: BLENDS },
21198
- pct("shadowOpacity", "Shadow opacity", e.shadowOpacity)
21199
- ];
21200
- case "satin":
21201
- return [
21202
- ...blended,
21203
- { key: "color", label: "Color", type: "color", value: e.color },
21204
- deg("angle", "Angle", e.angle),
21205
- px("distance", "Distance", e.distance),
21206
- px("size", "Size", e.size),
21207
- { key: "invert", label: "Invert", type: "checkbox", value: e.invert }
21208
- ];
21209
- case "color-overlay":
21210
- return [...blended, { key: "color", label: "Color", type: "color", value: e.color }];
21211
- case "gradient-overlay":
21212
- return [...blended, ...gradientControls("gradient", e.gradient)];
21213
- case "pattern-overlay":
21214
- return [
21215
- ...blended,
21216
- { key: "patternId", label: "Pattern", type: "select", value: e.patternId, options: patternOptions(patterns) },
21217
- pct("scale", "Scale", e.scale, 0.01, 10),
21218
- deg("angle", "Angle", e.angle ?? 0),
21219
- { key: "link", label: "Link with layer", type: "checkbox", value: e.link ?? true }
21220
- ];
21221
- case "stroke":
21222
- return [
21223
- ...blended,
21224
- px("size", "Size", e.size),
21225
- { key: "position", label: "Position", type: "select", value: e.position, options: opt(["outside", "Outside"], ["inside", "Inside"], ["center", "Center"]) },
21226
- ...fillControls(e.fill, true, patterns)
21227
- ];
21228
- }
21229
- }
21230
- function fillOfType(current, type, patterns) {
21231
- if (type === "gradient") return { type: "gradient", gradient: defaultEffectGradient() };
21232
- if (type === "pattern") return { type: "pattern", patternId: patterns[0]?.id ?? "checker", scale: 1 };
21233
- return { type: "color", color: current.type === "color" ? current.color : "#000000" };
21234
- }
21235
- function effectControlChange(effect, key2, value, patterns = []) {
21236
- const [top, ...rest] = key2.split(".");
21237
- if (top === "fill" && rest[0] === "type") return { fill: fillOfType(effect.fill, String(value), patterns) };
21238
- if (top === "patternId" && !rest.length) {
21239
- const name = patternOptions(patterns).find((o) => o.value === value)?.label;
21240
- return name ? { patternId: value, name } : { patternId: value };
21241
- }
21242
- if (!rest.length) return { [top]: value };
21243
- if (top === "fill" && rest[0] === "patternId") {
21244
- const name = patternOptions(patterns).find((o) => o.value === value)?.label;
21245
- return { fill: { ...effect.fill, patternId: value, ...name ? { name } : {} } };
21246
- }
21247
- return { [top]: setPath(getPath(effect, top), rest, value) };
21248
- }
21249
-
21250
20756
  // src/image-editor/layers/color-ui.ts
21251
20757
  var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
21252
20758
  var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
@@ -22846,10 +22352,10 @@ var ContentAwareFillSession = class _ContentAwareFillSession {
22846
22352
  const len2 = dx * dx + dy * dy;
22847
22353
  for (let y = y0; y <= y1; y++) {
22848
22354
  for (let x = x0; x <= x1; x++) {
22849
- const px2 = win.x + x + 0.5 - from.x;
22355
+ const px = win.x + x + 0.5 - from.x;
22850
22356
  const py = win.y + y + 0.5 - from.y;
22851
- const t = len2 > 0 ? Math.min(1, Math.max(0, (px2 * dx + py * dy) / len2)) : 0;
22852
- if ((px2 - t * dx) ** 2 + (py - t * dy) ** 2 > r * r) continue;
22357
+ const t = len2 > 0 ? Math.min(1, Math.max(0, (px * dx + py * dy) / len2)) : 0;
22358
+ if ((px - t * dx) ** 2 + (py - t * dy) ** 2 > r * r) continue;
22853
22359
  const i = y * win.width + x;
22854
22360
  area[i] = add2 && !hole[i] ? 1 : 0;
22855
22361
  }
@@ -23414,6 +22920,7 @@ export {
23414
22920
  createImageSubjectSelectionTool,
23415
22921
  createImageTransformTools,
23416
22922
  createImageTypeTools,
22923
+ createLayerEffectTools,
23417
22924
  createMetricTextShaper,
23418
22925
  createOutlineTextShaper,
23419
22926
  createPigment,