@pixerate/editor 0.246.0 → 0.249.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 (105) hide show
  1. package/README.md +1 -0
  2. package/dist/animation-editor/index.cjs +64 -61
  3. package/dist/animation-editor/index.js +8 -5
  4. package/dist/{brushstrokeRender-ZDHMXJAE.cjs → brushstrokeRender-GCKK7V2I.cjs} +14 -11
  5. package/dist/{brushstrokeRender-AKUI3SEJ.js → brushstrokeRender-T3JZST44.js} +7 -4
  6. package/dist/canvas/index.cjs +8 -8
  7. package/dist/canvas/index.js +1 -1
  8. package/dist/{chunk-UVPD55UZ.cjs → chunk-2SMMZDMG.cjs} +35 -35
  9. package/dist/chunk-2VJAVXLI.js +192 -0
  10. package/dist/{chunk-OLNIPTB3.cjs → chunk-2VX55NFM.cjs} +1 -320
  11. package/dist/chunk-3K6HWEXZ.cjs +92 -0
  12. package/dist/{chunk-UOOK7HTX.js → chunk-3PPJRMIG.js} +1 -1
  13. package/dist/chunk-4D6KP5BV.js +92 -0
  14. package/dist/chunk-5RH3VXAK.js +269 -0
  15. package/dist/{chunk-LDPLEZ5T.js → chunk-6BIDVPED.js} +1 -1
  16. package/dist/{chunk-2ONK3ERD.cjs → chunk-75K3W4D6.cjs} +20 -20
  17. package/dist/chunk-BOHDJJ2O.cjs +192 -0
  18. package/dist/{chunk-2PBZBRP5.js → chunk-D5KGAO4Z.js} +10 -92
  19. package/dist/{chunk-DQWPMGH2.js → chunk-DOIU7VJG.js} +1 -1
  20. package/dist/{chunk-HB4ICNNA.cjs → chunk-DPYAO5U6.cjs} +42 -42
  21. package/dist/chunk-EJLRBS5Q.js +301 -0
  22. package/dist/{chunk-Q2UYUWAZ.cjs → chunk-H4AOUUBE.cjs} +679 -164
  23. package/dist/{chunk-PQ3H2AAN.cjs → chunk-I7NJPHWV.cjs} +122 -204
  24. package/dist/{chunk-FK5LTDOO.cjs → chunk-IOFVM3L3.cjs} +7 -7
  25. package/dist/{chunk-42TWUPNJ.js → chunk-IRSTHLQQ.js} +1 -320
  26. package/dist/{chunk-VDAWA546.js → chunk-J7T5QZ45.js} +614 -99
  27. package/dist/{chunk-VMROIWLL.cjs → chunk-KBYB7OWB.cjs} +3 -3
  28. package/dist/{chunk-5MFDD7SP.cjs → chunk-KYX7NZ5V.cjs} +1 -1
  29. package/dist/chunk-LJRCU3BJ.cjs +301 -0
  30. package/dist/{chunk-XTWXBQD4.cjs → chunk-LP2MCSBE.cjs} +593 -236
  31. package/dist/{chunk-A23PSOBB.js → chunk-O75V4ZS3.js} +1 -1
  32. package/dist/chunk-OTTT5N3K.js +322 -0
  33. package/dist/{chunk-N6WUB3Y5.js → chunk-PZP2SZIZ.js} +2 -2
  34. package/dist/{chunk-4PMCMWQS.js → chunk-UBRJOIR5.js} +367 -10
  35. package/dist/chunk-W5M3J7PV.cjs +322 -0
  36. package/dist/{chunk-4P6H35HU.js → chunk-WA44NKPF.js} +2 -2
  37. package/dist/{chunk-CEPKXLBS.cjs → chunk-WLJZZHUZ.cjs} +23 -23
  38. package/dist/{chunk-P3NIPIKS.js → chunk-WQCNC4DK.js} +1 -1
  39. package/dist/chunk-ZEYMKDYS.cjs +269 -0
  40. package/dist/image-editor/effect-tools.d.cts +37 -4
  41. package/dist/image-editor/effect-tools.d.ts +37 -4
  42. package/dist/image-editor/index.cjs +1340 -1828
  43. package/dist/image-editor/index.d.cts +1 -1
  44. package/dist/image-editor/index.d.ts +1 -1
  45. package/dist/image-editor/index.js +298 -786
  46. package/dist/paint/index.cjs +8 -5
  47. package/dist/paint/index.js +13 -10
  48. package/dist/paint-editor/controller.d.cts +71 -2
  49. package/dist/paint-editor/controller.d.ts +71 -2
  50. package/dist/paint-editor/index.cjs +901 -589
  51. package/dist/paint-editor/index.d.cts +3 -0
  52. package/dist/paint-editor/index.d.ts +3 -0
  53. package/dist/paint-editor/index.js +365 -53
  54. package/dist/paint-editor/procedural.d.cts +82 -5
  55. package/dist/paint-editor/procedural.d.ts +82 -5
  56. package/dist/paint-editor/sticker-art.d.cts +55 -0
  57. package/dist/paint-editor/sticker-art.d.ts +55 -0
  58. package/dist/paint-editor/stickers.d.cts +30 -17
  59. package/dist/paint-editor/stickers.d.ts +30 -17
  60. package/dist/paint-editor/stroke.d.cts +4 -0
  61. package/dist/paint-editor/stroke.d.ts +4 -0
  62. package/dist/paint-editor/tools.d.cts +1 -1
  63. package/dist/paint-editor/tools.d.ts +1 -1
  64. package/dist/paint-editor/ui.d.cts +25 -4
  65. package/dist/paint-editor/ui.d.ts +25 -4
  66. package/dist/{image-editor/layers/effects-ui.d.cts → raster/effects/ui.d.cts} +32 -5
  67. package/dist/{image-editor/layers/effects-ui.d.ts → raster/effects/ui.d.ts} +32 -5
  68. package/dist/raster/index.cjs +17 -3
  69. package/dist/raster/index.d.cts +1 -0
  70. package/dist/raster/index.d.ts +1 -0
  71. package/dist/raster/index.js +23 -9
  72. package/dist/stickers/browser.d.cts +48 -0
  73. package/dist/stickers/browser.d.ts +48 -0
  74. package/dist/stickers/combine.d.cts +10 -0
  75. package/dist/stickers/combine.d.ts +10 -0
  76. package/dist/stickers/conformance.d.cts +18 -0
  77. package/dist/stickers/conformance.d.ts +18 -0
  78. package/dist/stickers/editor.d.cts +14 -0
  79. package/dist/stickers/editor.d.ts +14 -0
  80. package/dist/stickers/errors.d.cts +6 -0
  81. package/dist/stickers/errors.d.ts +6 -0
  82. package/dist/stickers/fake.d.cts +16 -0
  83. package/dist/stickers/fake.d.ts +16 -0
  84. package/dist/stickers/helpers.d.cts +51 -0
  85. package/dist/stickers/helpers.d.ts +51 -0
  86. package/dist/stickers/index.cjs +331 -0
  87. package/dist/stickers/index.d.cts +16 -0
  88. package/dist/stickers/index.d.ts +16 -0
  89. package/dist/stickers/index.js +331 -0
  90. package/dist/stickers/stamps.d.cts +13 -0
  91. package/dist/stickers/stamps.d.ts +13 -0
  92. package/dist/stickers/tools.d.cts +25 -0
  93. package/dist/stickers/tools.d.ts +25 -0
  94. package/dist/stickers/types.d.cts +123 -0
  95. package/dist/stickers/types.d.ts +123 -0
  96. package/dist/vector/index.cjs +978 -975
  97. package/dist/vector/index.js +9 -6
  98. package/package.json +11 -1
  99. package/skills/README.md +1 -0
  100. package/skills/pixerate-paint-editor/SKILL.md +26 -32
  101. package/skills/pixerate-paint-editor/references/gradient-paint.md +23 -0
  102. package/skills/pixerate-paint-editor/references/layer-effects.md +28 -0
  103. package/skills/pixerate-paint-editor/references/light-paint.md +10 -2
  104. package/skills/pixerate-paint-editor/references/particle-brushes.md +66 -0
  105. package/skills/pixerate-stickers/SKILL.md +45 -0
@@ -8,7 +8,7 @@ import {
8
8
  parseOpenTypeFont,
9
9
  removeAnchorsKeepingShape,
10
10
  traceField
11
- } from "../chunk-DQWPMGH2.js";
11
+ } from "../chunk-DOIU7VJG.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-UBRJOIR5.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-2VJAVXLI.js";
468
478
  import {
469
479
  DEFAULT_GLOBAL_LIGHT,
470
480
  INTERPOLATIONS,
@@ -514,7 +524,7 @@ import {
514
524
  validateLayerEffects,
515
525
  warpSurface,
516
526
  workingToSamples
517
- } from "../chunk-UOOK7HTX.js";
527
+ } from "../chunk-3PPJRMIG.js";
518
528
  import {
519
529
  applyHomography,
520
530
  boxQuad,
@@ -559,7 +569,7 @@ import {
559
569
  spotHealPixels,
560
570
  spotHealWindow,
561
571
  toneOf
562
- } from "../chunk-4P6H35HU.js";
572
+ } from "../chunk-WA44NKPF.js";
563
573
  import {
564
574
  bestOffset,
565
575
  contentAwareFill,
@@ -664,7 +674,7 @@ import {
664
674
  wetGpuSupport,
665
675
  wetSimdSupported,
666
676
  wetSupport
667
- } from "../chunk-P3NIPIKS.js";
677
+ } from "../chunk-WQCNC4DK.js";
668
678
  import {
669
679
  BUILTIN_PROFILES,
670
680
  CmsError,
@@ -733,8 +743,9 @@ import {
733
743
  warpMeshParamAt,
734
744
  warpMeshRows,
735
745
  warpPresetMesh
736
- } from "../chunk-N6WUB3Y5.js";
737
- import "../chunk-VDAWA546.js";
746
+ } from "../chunk-PZP2SZIZ.js";
747
+ import "../chunk-J7T5QZ45.js";
748
+ import "../chunk-5RH3VXAK.js";
738
749
  import "../chunk-M6DNZNVY.js";
739
750
  import {
740
751
  bezierPathToSvg,
@@ -792,7 +803,6 @@ import {
792
803
  StrokeCoverage,
793
804
  TIP_GRADIENT_STEPS,
794
805
  TileMedium,
795
- TileableNoise,
796
806
  addPaintGradientStop,
797
807
  applyStrokeToDeepTile,
798
808
  applyStrokeToTile,
@@ -812,12 +822,10 @@ import {
812
822
  gradientDabColor,
813
823
  grainCatch,
814
824
  grainHeights,
815
- hash2,
816
825
  hexToPaintRgb,
817
826
  isBrushstrokeBrush,
818
827
  isGradientPaint,
819
828
  loadMixer,
820
- mix32,
821
829
  mixerRates,
822
830
  normalizeBlender,
823
831
  normalizeBrush,
@@ -832,8 +840,6 @@ import {
832
840
  pathStrokeCoverage,
833
841
  pathStrokeDabs,
834
842
  put255,
835
- rand01,
836
- randSigned,
837
843
  rasterizeDab,
838
844
  readPaintSource,
839
845
  removePaintGradientStop,
@@ -841,7 +847,6 @@ import {
841
847
  resolvePaintGradient,
842
848
  reversePaintGradient,
843
849
  scalePaintGradient,
844
- seedFromString,
845
850
  smoothPoints,
846
851
  solidPaint,
847
852
  strokeGrainCatch,
@@ -850,7 +855,15 @@ import {
850
855
  tipShape,
851
856
  updatePaintGradientStop,
852
857
  walkDabs
853
- } from "../chunk-2PBZBRP5.js";
858
+ } from "../chunk-D5KGAO4Z.js";
859
+ import {
860
+ TileableNoise,
861
+ hash2,
862
+ mix32,
863
+ rand01,
864
+ randSigned,
865
+ seedFromString
866
+ } from "../chunk-4D6KP5BV.js";
854
867
  import {
855
868
  BRUSHSTROKE_MAX_SCALE,
856
869
  BRUSHSTROKE_MIN_SCALE,
@@ -865,25 +878,20 @@ import {
865
878
  PIGMENT_LAMBDA_STEP,
866
879
  PIGMENT_WAVELENGTHS,
867
880
  SHADOW_AMBIENT,
868
- base64ToBytes,
869
881
  blendChannel,
870
882
  blendImageData,
871
883
  blendLum,
872
884
  blendPixel,
873
885
  blendRgb,
874
- bytesToBase64,
875
886
  canvasCompositeOperation,
876
887
  convertSurfaceDepth,
877
888
  createPigment,
878
- decodePng,
879
889
  deepBytes,
880
890
  deepTile,
881
891
  depthOf,
882
- encodePng,
883
892
  isBitDepth,
884
893
  isBlendMode,
885
894
  isPainterlyBlendMode,
886
- isPng,
887
895
  isSeparableBlendMode,
888
896
  keepDeepSamples,
889
897
  lerpPigment,
@@ -892,9 +900,7 @@ import {
892
900
  mixPigmentRgb,
893
901
  mixPigments,
894
902
  normalizeBlendMode,
895
- parseDataUrl,
896
903
  pigment8,
897
- pngDataUrl,
898
904
  proxyOf,
899
905
  readDeepRegion,
900
906
  reflectanceToRgb,
@@ -916,7 +922,16 @@ import {
916
922
  to8From16,
917
923
  to8From32,
918
924
  writeDeepRegion
919
- } from "../chunk-42TWUPNJ.js";
925
+ } from "../chunk-IRSTHLQQ.js";
926
+ import {
927
+ base64ToBytes,
928
+ bytesToBase64,
929
+ decodePng,
930
+ encodePng,
931
+ isPng,
932
+ parseDataUrl,
933
+ pngDataUrl
934
+ } from "../chunk-OTTT5N3K.js";
920
935
  import {
921
936
  SurfaceDraft,
922
937
  TILE,
@@ -1686,13 +1701,13 @@ var ImageEditorRenderer = class {
1686
1701
  ctx.save();
1687
1702
  try {
1688
1703
  applyImageProjectionToContext(ctx, projection);
1689
- const px2 = u / (projection.scale || 1);
1704
+ const px = u / (projection.scale || 1);
1690
1705
  ctx.beginPath();
1691
- ctx.arc(b.x, b.y, Math.max(px2, b.diameter / 2), 0, Math.PI * 2);
1692
- ctx.lineWidth = 2 * px2;
1706
+ ctx.arc(b.x, b.y, Math.max(px, b.diameter / 2), 0, Math.PI * 2);
1707
+ ctx.lineWidth = 2 * px;
1693
1708
  ctx.strokeStyle = "rgba(0,0,0,0.6)";
1694
1709
  ctx.stroke();
1695
- ctx.lineWidth = px2;
1710
+ ctx.lineWidth = px;
1696
1711
  ctx.strokeStyle = "#ffffff";
1697
1712
  ctx.stroke();
1698
1713
  } catch {
@@ -2239,32 +2254,32 @@ var ImageEditorRenderer = class {
2239
2254
  this.outlineCache.set(selection, paths);
2240
2255
  }
2241
2256
  if (!paths.length) return;
2242
- const px2 = 1 / (scale || 1);
2257
+ const px = 1 / (scale || 1);
2243
2258
  ctx.beginPath();
2244
2259
  for (const p of paths) {
2245
2260
  ctx.moveTo(p[0], p[1]);
2246
2261
  for (let i = 2; i < p.length; i += 2) ctx.lineTo(p[i], p[i + 1]);
2247
2262
  }
2248
- ctx.lineWidth = px2;
2263
+ ctx.lineWidth = px;
2249
2264
  ctx.strokeStyle = "#ffffff";
2250
2265
  ctx.stroke();
2251
2266
  if (typeof ctx.setLineDash === "function") {
2252
- ctx.setLineDash([4 * px2, 4 * px2]);
2253
- ctx.lineDashOffset = -offset * px2;
2267
+ ctx.setLineDash([4 * px, 4 * px]);
2268
+ ctx.lineDashOffset = -offset * px;
2254
2269
  }
2255
2270
  ctx.strokeStyle = "#000000";
2256
2271
  ctx.stroke();
2257
2272
  if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
2258
2273
  }
2259
2274
  drawDraftPath(ctx, points, scale) {
2260
- const px2 = 1 / (scale || 1);
2275
+ const px = 1 / (scale || 1);
2261
2276
  ctx.beginPath();
2262
2277
  points.forEach((p, i) => i === 0 ? ctx.moveTo(p.x, p.y) : ctx.lineTo(p.x, p.y));
2263
2278
  ctx.closePath();
2264
- ctx.lineWidth = px2;
2279
+ ctx.lineWidth = px;
2265
2280
  ctx.strokeStyle = "#ffffff";
2266
2281
  ctx.stroke();
2267
- if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px2, 4 * px2]);
2282
+ if (typeof ctx.setLineDash === "function") ctx.setLineDash([4 * px, 4 * px]);
2268
2283
  ctx.strokeStyle = "#000000";
2269
2284
  ctx.stroke();
2270
2285
  if (typeof ctx.setLineDash === "function") ctx.setLineDash([]);
@@ -2929,9 +2944,9 @@ function inspectMaskEdge(mask, image, options = {}) {
2929
2944
  turnExcess += Math.max(0, total - closure);
2930
2945
  outline += L;
2931
2946
  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));
2947
+ const [px, py] = pts[i];
2948
+ if (px < 0 || py < 0 || px >= W || py >= H) continue;
2949
+ const blk = block(Math.floor(px), Math.floor(py));
2935
2950
  blk.turn += Math.abs(turns[i]) - closure / n;
2936
2951
  blk.len += 2;
2937
2952
  }
@@ -4118,10 +4133,10 @@ function liveWire(map, from, to, band) {
4118
4133
  const uy = (by - ay) / len;
4119
4134
  for (let y = 0; y < h; y++) {
4120
4135
  for (let x = 0; x < w; x++) {
4121
- const px2 = rx0 + x - ax;
4136
+ const px = rx0 + x - ax;
4122
4137
  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;
4138
+ const t = Math.min(len, Math.max(0, px * ux + py * uy));
4139
+ if (Math.hypot(px - t * ux, py - t * uy) > half) continue;
4125
4140
  const i = y * w + x;
4126
4141
  inside[i] = 1;
4127
4142
  const f = map.features(rx0 + x, ry0 + y);
@@ -5015,43 +5030,43 @@ function liftPixels(surface, sel, o) {
5015
5030
  const area = { x: sb.x - o.x, y: sb.y - o.y, width: sb.width, height: sb.height };
5016
5031
  const depth = surfaceDepth(surface);
5017
5032
  if (depth !== 8) {
5018
- const px3 = readDeepRegion(surface, area, depth);
5019
- const kept2 = px3.slice();
5033
+ const px2 = readDeepRegion(surface, area, depth);
5034
+ const kept2 = px2.slice();
5020
5035
  const r16 = depth === 16;
5021
5036
  for (let y = 0; y < area.height; y++) {
5022
5037
  for (let x = 0; x < area.width; x++) {
5023
5038
  const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
5024
5039
  const i = (y * area.width + x) * 4;
5025
5040
  if (k <= 0) {
5026
- px3[i] = px3[i + 1] = px3[i + 2] = px3[i + 3] = 0;
5041
+ px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
5027
5042
  continue;
5028
5043
  }
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;
5044
+ px2[i + 3] = r16 ? Math.round(px2[i + 3] * k) : px2[i + 3] * k;
5045
+ if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
5031
5046
  kept2[i + 3] = r16 ? Math.round(kept2[i + 3] * (1 - k)) : kept2[i + 3] * (1 - k);
5032
5047
  if (!kept2[i + 3]) kept2[i] = kept2[i + 1] = kept2[i + 2] = 0;
5033
5048
  }
5034
5049
  }
5035
- const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px3);
5050
+ const lifted = writeDeepRegion(new TiledSurface(4, /* @__PURE__ */ new Map(), 0), area, px2);
5036
5051
  return { lifted, rest: writeDeepRegion(surface, area, kept2) };
5037
5052
  }
5038
- const px2 = readRegion(surface, area);
5039
- const kept = new Uint8ClampedArray(px2);
5053
+ const px = readRegion(surface, area);
5054
+ const kept = new Uint8ClampedArray(px);
5040
5055
  for (let y = 0; y < area.height; y++) {
5041
5056
  for (let x = 0; x < area.width; x++) {
5042
5057
  const k = sel.data[(sb.y + y) * sel.width + sb.x + x] / 255;
5043
5058
  const i = (y * area.width + x) * 4;
5044
5059
  if (k <= 0) {
5045
- px2[i] = px2[i + 1] = px2[i + 2] = px2[i + 3] = 0;
5060
+ px[i] = px[i + 1] = px[i + 2] = px[i + 3] = 0;
5046
5061
  continue;
5047
5062
  }
5048
- px2[i + 3] = px2[i + 3] * k;
5049
- if (!px2[i + 3]) px2[i] = px2[i + 1] = px2[i + 2] = 0;
5063
+ px[i + 3] = px[i + 3] * k;
5064
+ if (!px[i + 3]) px[i] = px[i + 1] = px[i + 2] = 0;
5050
5065
  kept[i + 3] = kept[i + 3] * (1 - k);
5051
5066
  if (!kept[i + 3]) kept[i] = kept[i + 1] = kept[i + 2] = 0;
5052
5067
  }
5053
5068
  }
5054
- return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px2 }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
5069
+ return { lifted: surfaceFromPixels({ width: area.width, height: area.height, data: px }, 4, area.x, area.y), rest: writeRegion(surface, area, kept) };
5055
5070
  }
5056
5071
  function liftMask(mask, sel, o) {
5057
5072
  const sb = sel.bounds;
@@ -5642,14 +5657,14 @@ function displayTransform(doc, proof) {
5642
5657
  const g = gamut;
5643
5658
  return (rgba) => {
5644
5659
  if (g) {
5645
- const px2 = [0, 0, 0];
5660
+ const px = [0, 0, 0];
5646
5661
  const flags = new Uint8Array(rgba.length >> 2);
5647
5662
  for (let i = 0, p = 0; i < rgba.length; i += 4, p++) {
5648
5663
  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;
5664
+ px[0] = rgba[i] / 255;
5665
+ px[1] = rgba[i + 1] / 255;
5666
+ px[2] = rgba[i + 2] / 255;
5667
+ if (g.outOfGamut(px)) flags[p] = 1;
5653
5668
  }
5654
5669
  tr.convert8(rgba, 4, rgba, 4);
5655
5670
  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 +6468,12 @@ var ImageEditorController = class {
6453
6468
  } else {
6454
6469
  const sb = sel.bounds;
6455
6470
  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);
6471
+ const px = readRegion(surface, src);
6457
6472
  const data = sel.data;
6458
6473
  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));
6474
+ 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
6475
  }
6461
- copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px2 }, 4, src.x, src.y) };
6476
+ copy = { ...layer, id: newLayerId(), surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y) };
6462
6477
  delete copy.mask;
6463
6478
  }
6464
6479
  delete copy.source;
@@ -7109,9 +7124,9 @@ var ImageEditorController = class {
7109
7124
  const bounds = this.getLayerBounds(layer.id);
7110
7125
  if (bounds && point2.x >= bounds.x && point2.x <= bounds.x + bounds.width && point2.y >= bounds.y && point2.y <= bounds.y + bounds.height) {
7111
7126
  const surface = this.surfaceOf(layer);
7112
- const px2 = Math.floor(point2.x - layer.offset.x);
7127
+ const px = Math.floor(point2.x - layer.offset.x);
7113
7128
  const py = Math.floor(point2.y - layer.offset.y);
7114
- const pixel = readPixel(surface, px2, py);
7129
+ const pixel = readPixel(surface, px, py);
7115
7130
  if (pixel.length >= 4 && pixel[3] >= alphaThreshold) return layer.id;
7116
7131
  }
7117
7132
  return null;
@@ -7123,9 +7138,9 @@ var ImageEditorController = class {
7123
7138
  return null;
7124
7139
  }
7125
7140
  const surface = this.surfaceOf(layer);
7126
- const px2 = Math.floor(point2.x - layer.offset.x);
7141
+ const px = Math.floor(point2.x - layer.offset.x);
7127
7142
  const py = Math.floor(point2.y - layer.offset.y);
7128
- const pixel = readPixel(surface, px2, py);
7143
+ const pixel = readPixel(surface, px, py);
7129
7144
  if (pixel.length >= 4 && pixel[3] >= alphaThreshold) {
7130
7145
  return layer.id;
7131
7146
  }
@@ -7276,17 +7291,17 @@ var ImageEditorController = class {
7276
7291
  */
7277
7292
  sourceSurface() {
7278
7293
  const { width, height } = this.naturalSize;
7279
- const fromPixels = (px3) => {
7280
- let s = this.sourceSurfaces.get(px3);
7294
+ const fromPixels = (px2) => {
7295
+ let s = this.sourceSurfaces.get(px2);
7281
7296
  if (!s) {
7282
- s = surfaceFromPixels(px3, 4);
7283
- this.sourceSurfaces.set(px3, s);
7297
+ s = surfaceFromPixels(px2, 4);
7298
+ this.sourceSurfaces.set(px2, s);
7284
7299
  }
7285
7300
  return s;
7286
7301
  };
7287
- const px2 = this.samplePixels;
7288
- const fits = Boolean(px2 && px2.width === width && px2.height === height);
7289
- if (this.samplePixelsOverride && fits) return fromPixels(px2);
7302
+ const px = this.samplePixels;
7303
+ const fits = Boolean(px && px.width === width && px.height === height);
7304
+ if (this.samplePixelsOverride && fits) return fromPixels(px);
7290
7305
  const el = this.imageElement;
7291
7306
  if (el) {
7292
7307
  const cached = this.sourceSurfaces.get(el);
@@ -7300,7 +7315,7 @@ var ImageEditorController = class {
7300
7315
  return s;
7301
7316
  }
7302
7317
  }
7303
- return fits ? fromPixels(px2) : null;
7318
+ return fits ? fromPixels(px) : null;
7304
7319
  }
7305
7320
  opaqueCache = /* @__PURE__ */ new WeakMap();
7306
7321
  /** Whether every source pixel is opaque (some legacy renders depend on it). */
@@ -7362,11 +7377,11 @@ var ImageEditorController = class {
7362
7377
  const { width, height } = this.naturalSize;
7363
7378
  let surface = emptySurface(4);
7364
7379
  if (init.pixels) {
7365
- const px2 = init.pixels;
7366
- if (!(px2.width > 0 && px2.height > 0) || px2.data.length < px2.width * px2.height * 4) {
7380
+ const px = init.pixels;
7381
+ if (!(px.width > 0 && px.height > 0) || px.data.length < px.width * px.height * 4) {
7367
7382
  throw new LayerOperationError("pixels must be RGBA with width \xD7 height \xD7 4 bytes.");
7368
7383
  }
7369
- surface = surfaceFromPixels(px2, 4);
7384
+ surface = surfaceFromPixels(px, 4);
7370
7385
  } else if (init.color !== void 0) {
7371
7386
  const c = parseColor(init.color);
7372
7387
  surface = solidSurface(4, { x: 0, y: 0, width, height }, packRgba(c[0], c[1], c[2], c[3]));
@@ -7470,9 +7485,9 @@ var ImageEditorController = class {
7470
7485
  getEdgeColor(id) {
7471
7486
  const layer = this.requireEdgeLayer(id);
7472
7487
  const e = layer.edge ?? {};
7473
- const pct2 = (v) => Math.round((v ?? 0) * 1e3) / 10;
7488
+ const pct = (v) => Math.round((v ?? 0) * 1e3) / 10;
7474
7489
  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" };
7490
+ return { layerId: layer.id, decontaminate: pct(e.decontaminate), despill: pct(e.despill), ambient: pct(e.ambient), ambientSource: e.ambientColor ? hex(e.ambientColor) : "auto" };
7476
7491
  }
7477
7492
  requireEdgeLayer(id) {
7478
7493
  const layer = this.getLayer(id);
@@ -7527,9 +7542,9 @@ var ImageEditorController = class {
7527
7542
  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
7543
  }
7529
7544
  if (turningOn("ambient") && !this.maskHasSoftBand(layer) && layer.type === "pixel") {
7530
- const px2 = this.getLayerPixels(layer.id);
7545
+ const px = this.getLayerPixels(layer.id);
7531
7546
  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;
7547
+ if (px) for (let i = 3; i < px.data.length && !soft; i += 4) soft = px.data[i] > 5 && px.data[i] < 250;
7533
7548
  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
7549
  }
7535
7550
  const edge = next.decontaminate || next.despill || next.ambient || next.ambientColor ? next : void 0;
@@ -8155,14 +8170,14 @@ var ImageEditorController = class {
8155
8170
  const surface = this.surfaceOf(layer);
8156
8171
  const sb = sel.bounds;
8157
8172
  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;
8173
+ const px = readRegion(surface, src);
8174
+ const kept = options.cut ? new Uint8ClampedArray(px) : null;
8160
8175
  for (let y = 0; y < sb.height; y++) {
8161
8176
  for (let x = 0; x < sb.width; x++) {
8162
8177
  const c = sel.data[(sb.y + y) * sel.width + sb.x + x];
8163
8178
  const i = (y * sb.width + x) * 4 + 3;
8164
8179
  if (kept) kept[i] = Math.round(kept[i] * (1 - c / 255));
8165
- px2[i] = Math.round(px2[i] * (c / 255));
8180
+ px[i] = Math.round(px[i] * (c / 255));
8166
8181
  }
8167
8182
  }
8168
8183
  const copy = {
@@ -8172,7 +8187,7 @@ var ImageEditorController = class {
8172
8187
  visible: true,
8173
8188
  opacity: 1,
8174
8189
  blend: "normal",
8175
- surface: surfaceFromPixels({ width: src.width, height: src.height, data: px2 }, 4, src.x, src.y),
8190
+ surface: surfaceFromPixels({ width: src.width, height: src.height, data: px }, 4, src.x, src.y),
8176
8191
  offset: { ...layer.offset }
8177
8192
  };
8178
8193
  let next = insertLayer(this.state.layers, copy, loc.parent?.id ?? null, loc.index + 1);
@@ -8609,8 +8624,8 @@ var ImageEditorController = class {
8609
8624
  for (const [cid, c] of pending) {
8610
8625
  try {
8611
8626
  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 };
8627
+ const px = await this.decodeImage(url);
8628
+ const decoded = { ...c, kind: "raster", raster: rasterContents(px, c.name, cid).raster, width: px.width, height: px.height };
8614
8629
  const swap = (layers) => {
8615
8630
  let out = layers;
8616
8631
  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 +8721,8 @@ var ImageEditorController = class {
8706
8721
  const only = edited.layers.length === 1 ? edited.layers[0] : null;
8707
8722
  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
8723
  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);
8724
+ const px = readRegion(only.surface, { x: -only.offset.x, y: -only.offset.y, width, height });
8725
+ next = rasterContents({ width, height, data: px }, old.name, old.id);
8711
8726
  } else {
8712
8727
  const doc = { layers: edited.layers, globalLight: edited.globalLight, patterns: edited.patterns };
8713
8728
  next = documentContents(doc, width, height, old?.kind === "document" ? old.name : `${(old?.name ?? "Contents").replace(/\.\w+$/, "")}.psb`, top.contentsId);
@@ -11499,9 +11514,9 @@ var ImageEditorController = class {
11499
11514
  return;
11500
11515
  }
11501
11516
  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);
11517
+ let px = await this.decodeImage(newDataUrl);
11518
+ if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
11519
+ const data = new Uint8ClampedArray(px.data);
11505
11520
  const sel = this.state.selection?.bounds ? this.state.selection : null;
11506
11521
  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
11522
  return this.addPixelLayer({ name: "Inpaint", pixels: { width, height, data } });
@@ -11522,10 +11537,10 @@ var ImageEditorController = class {
11522
11537
  if (!target) throw new LayerOperationError("There is no pixel layer to mask.");
11523
11538
  requireUnlocked(target, "all", "mask it");
11524
11539
  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);
11540
+ let px = await this.decodeImage(newDataUrl);
11541
+ if (px.width !== width || px.height !== height) px = resizePixels(px, width, height);
11527
11542
  const alpha = new Uint8ClampedArray(width * height);
11528
- for (let p = 0; p < alpha.length; p++) alpha[p] = px2.data[p * 4 + 3];
11543
+ for (let p = 0; p < alpha.length; p++) alpha[p] = px.data[p * 4 + 3];
11529
11544
  let surface = surfaceFromPixels({ width, height, data: alpha }, 1, 0, 0, 0);
11530
11545
  if (target.offset.x || target.offset.y) surface = translateSurface(surface, -target.offset.x, -target.offset.y);
11531
11546
  this.commitLayers(setLayerMask(this.state.layers, target.id, { surface, defaultValue: 0 }));
@@ -12098,14 +12113,14 @@ var ImageEditorController = class {
12098
12113
  const converted = [];
12099
12114
  const unconverted = [];
12100
12115
  const memo = /* @__PURE__ */ new Map();
12101
- const px2 = new Float32Array(4);
12116
+ const px = new Float32Array(4);
12102
12117
  const hex = (h) => {
12103
12118
  let out = memo.get(h.toLowerCase());
12104
12119
  if (out === void 0) {
12105
12120
  const n = parseInt(h.slice(1), 16);
12106
- t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px2);
12121
+ t.eval([(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255], px);
12107
12122
  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])}`;
12123
+ out = `#${c(px[0])}${c(px[1])}${c(px[2])}`;
12109
12124
  memo.set(h.toLowerCase(), out);
12110
12125
  }
12111
12126
  return out;
@@ -12914,24 +12929,24 @@ function pixelsOnly(layers) {
12914
12929
  }
12915
12930
  return out;
12916
12931
  }
12917
- function resizePixels(px2, width, height) {
12918
- const src = px2.data;
12932
+ function resizePixels(px, width, height) {
12933
+ const src = px.data;
12919
12934
  const out = new Uint8ClampedArray(width * height * 4);
12920
- const kx = px2.width / width;
12921
- const ky = px2.height / height;
12935
+ const kx = px.width / width;
12936
+ const ky = px.height / height;
12922
12937
  for (let y = 0; y < height; y++) {
12923
- const fy = Math.min(px2.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
12938
+ const fy = Math.min(px.height - 1, Math.max(0, (y + 0.5) * ky - 0.5));
12924
12939
  const y0 = Math.floor(fy);
12925
- const y1 = Math.min(px2.height - 1, y0 + 1);
12940
+ const y1 = Math.min(px.height - 1, y0 + 1);
12926
12941
  const ty = fy - y0;
12927
12942
  for (let x = 0; x < width; x++) {
12928
- const fx = Math.min(px2.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
12943
+ const fx = Math.min(px.width - 1, Math.max(0, (x + 0.5) * kx - 0.5));
12929
12944
  const x0 = Math.floor(fx);
12930
- const x1 = Math.min(px2.width - 1, x0 + 1);
12945
+ const x1 = Math.min(px.width - 1, x0 + 1);
12931
12946
  const tx = fx - x0;
12932
12947
  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;
12948
+ const a = src[(y0 * px.width + x0) * 4 + c] * (1 - tx) + src[(y0 * px.width + x1) * 4 + c] * tx;
12949
+ const b = src[(y1 * px.width + x0) * 4 + c] * (1 - tx) + src[(y1 * px.width + x1) * 4 + c] * tx;
12935
12950
  out[(y * width + x) * 4 + c] = a * (1 - ty) + b * ty;
12936
12951
  }
12937
12952
  }
@@ -13803,8 +13818,8 @@ var REFINE_OUTPUTS = [
13803
13818
  ];
13804
13819
  function describeSelection(mask) {
13805
13820
  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;
13821
+ const pct = selectionArea(mask) / (mask.width * mask.height) * 100;
13822
+ const shown = pct >= 10 ? Math.round(pct) : Math.round(pct * 10) / 10;
13808
13823
  return `${mask.bounds.width} \xD7 ${mask.bounds.height} px selected (${shown}% of the image)`;
13809
13824
  }
13810
13825
 
@@ -15341,14 +15356,14 @@ function rebin(bins, count) {
15341
15356
  return out;
15342
15357
  }
15343
15358
  function histogramSummary(h, bins) {
15344
- const pct2 = (n) => h.samples ? round(n / h.samples * 100) : 0;
15359
+ const pct = (n) => h.samples ? round(n / h.samples * 100) : 0;
15345
15360
  const channels = { red: h.red, green: h.green, blue: h.blue, luminance: h.luminance };
15346
15361
  return {
15347
15362
  samples: h.samples,
15348
15363
  transparent: h.transparent,
15349
15364
  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]) }
15365
+ shadowsPercent: { red: pct(h.shadows[0]), green: pct(h.shadows[1]), blue: pct(h.shadows[2]) },
15366
+ highlightsPercent: { red: pct(h.highlights[0]), green: pct(h.highlights[1]), blue: pct(h.highlights[2]) }
15352
15367
  },
15353
15368
  stats: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, binStats(v, h.samples)])),
15354
15369
  ...bins ? { bins: Object.fromEntries(Object.entries(channels).map(([k, v]) => [k, rebin(v, bins)])) } : {}
@@ -16249,337 +16264,6 @@ function createImageLayerTools(controller) {
16249
16264
  ];
16250
16265
  }
16251
16266
 
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
16267
  // src/image-editor/selection/gesture.ts
16584
16268
  function snapTo45(from, point2) {
16585
16269
  const dx = point2.x - from.x;
@@ -17315,10 +16999,10 @@ var PaintGesture = class {
17315
16999
  };
17316
17000
 
17317
17001
  // 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 };
17002
+ var READ3 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17003
+ var WRITE3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17320
17004
  var SET = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17321
- var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
17005
+ var DESTRUCTIVE2 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
17322
17006
  var TARGET = {
17323
17007
  layerId: { type: "string", description: "Layer to paint (default the active layer; see list_layers)." },
17324
17008
  channel: {
@@ -17408,7 +17092,7 @@ function createImagePaintTools(controller) {
17408
17092
  required: ["points"],
17409
17093
  additionalProperties: false
17410
17094
  },
17411
- annotations: { title: "Paint a brush stroke", ...WRITE4 },
17095
+ annotations: { title: "Paint a brush stroke", ...WRITE3 },
17412
17096
  handler: (args) => {
17413
17097
  const tool = args.tool;
17414
17098
  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 +17115,7 @@ function createImagePaintTools(controller) {
17431
17115
  title: "Get the Mixer Brush",
17432
17116
  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
17117
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17434
- annotations: { title: "Get the Mixer Brush", ...READ4 },
17118
+ annotations: { title: "Get the Mixer Brush", ...READ3 },
17435
17119
  handler: () => {
17436
17120
  const { mixer, mixerLoad } = controller.getState().paint;
17437
17121
  return { settings: { ...mixer }, load: mixerLoadResult(mixerLoad) };
@@ -17446,7 +17130,7 @@ function createImagePaintTools(controller) {
17446
17130
  properties: { color: { type: "string", description: "Paint colour #rrggbb (default the foreground)." } },
17447
17131
  additionalProperties: false
17448
17132
  },
17449
- annotations: { title: "Load the Mixer Brush", ...WRITE4, idempotentHint: true },
17133
+ annotations: { title: "Load the Mixer Brush", ...WRITE3, idempotentHint: true },
17450
17134
  handler: (args) => mixerLoadResult(controller.loadMixerBrush(args.color))
17451
17135
  };
17452
17136
  const cleanMixerTool = {
@@ -17458,7 +17142,7 @@ function createImagePaintTools(controller) {
17458
17142
  properties: { emptyReservoir: { type: "boolean", description: "Also drop the reservoir (default false)." } },
17459
17143
  additionalProperties: false
17460
17144
  },
17461
- annotations: { title: "Clean the Mixer Brush", ...WRITE4, idempotentHint: true },
17145
+ annotations: { title: "Clean the Mixer Brush", ...WRITE3, idempotentHint: true },
17462
17146
  handler: (args) => mixerLoadResult(args.emptyReservoir === true ? controller.emptyMixerBrush() : controller.cleanMixerBrush())
17463
17147
  };
17464
17148
  const fill = {
@@ -17476,7 +17160,7 @@ function createImagePaintTools(controller) {
17476
17160
  },
17477
17161
  additionalProperties: false
17478
17162
  },
17479
- annotations: { title: "Fill pixels", ...WRITE4 },
17163
+ annotations: { title: "Fill pixels", ...WRITE3 },
17480
17164
  handler: (args) => controller.fillPixels({
17481
17165
  color: args.color,
17482
17166
  opacity: args.opacity,
@@ -17498,7 +17182,7 @@ function createImagePaintTools(controller) {
17498
17182
  },
17499
17183
  additionalProperties: false
17500
17184
  },
17501
- annotations: { title: "Clear pixels", ...DESTRUCTIVE3 },
17185
+ annotations: { title: "Clear pixels", ...DESTRUCTIVE2 },
17502
17186
  handler: (args) => controller.clearPixels({ opacity: args.opacity, useSelection: args.useSelection, ...readTarget(args) })
17503
17187
  };
17504
17188
  const paintView = () => {
@@ -17521,7 +17205,7 @@ function createImagePaintTools(controller) {
17521
17205
  title: "Get the paint",
17522
17206
  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
17207
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17524
- annotations: { title: "Get the paint", ...READ4 },
17208
+ annotations: { title: "Get the paint", ...READ3 },
17525
17209
  handler: () => paintView()
17526
17210
  };
17527
17211
  const sampleColor2 = {
@@ -17564,7 +17248,7 @@ function createImagePaintTools(controller) {
17564
17248
  required: ["start", "end"],
17565
17249
  additionalProperties: false
17566
17250
  },
17567
- annotations: { title: "Sample a gradient along a line", ...READ4 },
17251
+ annotations: { title: "Sample a gradient along a line", ...READ3 },
17568
17252
  handler: (args) => {
17569
17253
  const start = args.start;
17570
17254
  const end = args.end;
@@ -17593,7 +17277,7 @@ function createImagePaintTools(controller) {
17593
17277
  }
17594
17278
 
17595
17279
  // src/image-editor/color-tools.ts
17596
- var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17280
+ var READ4 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17597
17281
  var PROFILE = {
17598
17282
  type: "string",
17599
17283
  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 +17304,7 @@ function createImageColorTools(controller) {
17620
17304
  title: "Get the colour profile",
17621
17305
  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
17306
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17623
- annotations: { title: "Get the colour profile", ...READ5 },
17307
+ annotations: { title: "Get the colour profile", ...READ4 },
17624
17308
  handler: () => {
17625
17309
  const proof2 = controller.getState().proofSetup;
17626
17310
  return {
@@ -17704,7 +17388,7 @@ function createImageColorTools(controller) {
17704
17388
  required: ["colors", "to"],
17705
17389
  additionalProperties: false
17706
17390
  },
17707
- annotations: { title: "Convert colours between profiles", ...READ5 },
17391
+ annotations: { title: "Convert colours between profiles", ...READ4 },
17708
17392
  handler: (args) => ({
17709
17393
  colors: controller.convertColors(args.colors, profileArg(args.to), {
17710
17394
  ...args.from !== void 0 ? { from: profileArg(args.from) } : {},
@@ -17740,8 +17424,8 @@ function createImageColorTools(controller) {
17740
17424
  }
17741
17425
 
17742
17426
  // 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 };
17427
+ var READ5 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17428
+ var WRITE4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
17745
17429
  var POINTS = {
17746
17430
  type: "array",
17747
17431
  minItems: 1,
@@ -17831,7 +17515,7 @@ function createImageRetouchTools(controller) {
17831
17515
  required: ["points"],
17832
17516
  additionalProperties: false
17833
17517
  },
17834
- annotations: { title: "Clone Stamp stroke", ...WRITE5 },
17518
+ annotations: { title: "Clone Stamp stroke", ...WRITE4 },
17835
17519
  handler: (args) => stroke("clone", args, pick(args, ["aligned", "sample"]))
17836
17520
  };
17837
17521
  const healBrush = {
@@ -17851,7 +17535,7 @@ function createImageRetouchTools(controller) {
17851
17535
  required: ["points"],
17852
17536
  additionalProperties: false
17853
17537
  },
17854
- annotations: { title: "Healing Brush stroke", ...WRITE5 },
17538
+ annotations: { title: "Healing Brush stroke", ...WRITE4 },
17855
17539
  handler: (args) => stroke("heal", args, pick(args, ["aligned", "sample"]))
17856
17540
  };
17857
17541
  const spotHeal = {
@@ -17870,7 +17554,7 @@ function createImageRetouchTools(controller) {
17870
17554
  required: ["points"],
17871
17555
  additionalProperties: false
17872
17556
  },
17873
- annotations: { title: "Spot Healing stroke", ...WRITE5 },
17557
+ annotations: { title: "Spot Healing stroke", ...WRITE4 },
17874
17558
  handler: (args) => stroke("spot-heal", args, { ...pick(args, ["sample"]), ...args.type !== void 0 ? { spotType: args.type } : {} })
17875
17559
  };
17876
17560
  const smudge = {
@@ -17888,7 +17572,7 @@ function createImageRetouchTools(controller) {
17888
17572
  required: ["points"],
17889
17573
  additionalProperties: false
17890
17574
  },
17891
- annotations: { title: "Smudge stroke", ...WRITE5 },
17575
+ annotations: { title: "Smudge stroke", ...WRITE4 },
17892
17576
  handler: (args) => stroke("smudge", args, pick(args, ["strength"]))
17893
17577
  };
17894
17578
  const toneSchema = (verb) => ({
@@ -17909,7 +17593,7 @@ function createImageRetouchTools(controller) {
17909
17593
  title: "Dodge stroke",
17910
17594
  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
17595
  inputSchema: toneSchema("lighten"),
17912
- annotations: { title: "Dodge stroke", ...WRITE5 },
17596
+ annotations: { title: "Dodge stroke", ...WRITE4 },
17913
17597
  handler: (args) => stroke("dodge", args, pick(args, ["range", "exposure", "protectTones"]))
17914
17598
  };
17915
17599
  const burn = {
@@ -17917,7 +17601,7 @@ function createImageRetouchTools(controller) {
17917
17601
  title: "Burn stroke",
17918
17602
  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
17603
  inputSchema: toneSchema("darken"),
17920
- annotations: { title: "Burn stroke", ...WRITE5 },
17604
+ annotations: { title: "Burn stroke", ...WRITE4 },
17921
17605
  handler: (args) => stroke("burn", args, pick(args, ["range", "exposure", "protectTones"]))
17922
17606
  };
17923
17607
  const spongeTool = {
@@ -17936,7 +17620,7 @@ function createImageRetouchTools(controller) {
17936
17620
  required: ["points"],
17937
17621
  additionalProperties: false
17938
17622
  },
17939
- annotations: { title: "Sponge stroke", ...WRITE5 },
17623
+ annotations: { title: "Sponge stroke", ...WRITE4 },
17940
17624
  handler: (args) => stroke("sponge", { ...args, channel: "pixels" }, { ...pick(args, ["vibrance"]), ...args.mode !== void 0 ? { spongeMode: args.mode } : {} })
17941
17625
  };
17942
17626
  const filterSchema = (verb) => ({
@@ -17955,7 +17639,7 @@ function createImageRetouchTools(controller) {
17955
17639
  title: "Blur stroke",
17956
17640
  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
17641
  inputSchema: filterSchema("blur"),
17958
- annotations: { title: "Blur stroke", ...WRITE5 },
17642
+ annotations: { title: "Blur stroke", ...WRITE4 },
17959
17643
  handler: (args) => stroke("blur", args, pick(args, ["strength"]))
17960
17644
  };
17961
17645
  const sharpenTool = {
@@ -17963,7 +17647,7 @@ function createImageRetouchTools(controller) {
17963
17647
  title: "Sharpen stroke",
17964
17648
  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
17649
  inputSchema: filterSchema("sharpen"),
17966
- annotations: { title: "Sharpen stroke", ...WRITE5 },
17650
+ annotations: { title: "Sharpen stroke", ...WRITE4 },
17967
17651
  handler: (args) => stroke("sharpen", args, pick(args, ["strength"]))
17968
17652
  };
17969
17653
  const historyBrush = {
@@ -17981,7 +17665,7 @@ function createImageRetouchTools(controller) {
17981
17665
  required: ["points"],
17982
17666
  additionalProperties: false
17983
17667
  },
17984
- annotations: { title: "History Brush stroke", ...WRITE5 },
17668
+ annotations: { title: "History Brush stroke", ...WRITE4 },
17985
17669
  handler: (args) => stroke("history", args, pick(args, ["historySteps"]))
17986
17670
  };
17987
17671
  const getOptions = {
@@ -17989,7 +17673,7 @@ function createImageRetouchTools(controller) {
17989
17673
  title: "Get retouch options",
17990
17674
  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
17675
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
17992
- annotations: { title: "Get retouch options", ...READ6 },
17676
+ annotations: { title: "Get retouch options", ...READ5 },
17993
17677
  handler: () => {
17994
17678
  const { retouch, cloneSource, cloneTransform } = controller.getState().paint;
17995
17679
  return { options: { ...retouch }, cloneSource: cloneSource ? { ...cloneSource } : null, cloneTransform: { ...cloneTransform } };
@@ -18015,7 +17699,7 @@ function createImageRetouchTools(controller) {
18015
17699
  },
18016
17700
  additionalProperties: false
18017
17701
  },
18018
- annotations: { title: "Set retouch options", ...WRITE5, idempotentHint: true },
17702
+ annotations: { title: "Set retouch options", ...WRITE4, idempotentHint: true },
18019
17703
  handler: (args) => ({ ...controller.setPaintOptions({ retouch: args }).retouch })
18020
17704
  };
18021
17705
  const setSource = {
@@ -18031,7 +17715,7 @@ function createImageRetouchTools(controller) {
18031
17715
  },
18032
17716
  additionalProperties: false
18033
17717
  },
18034
- annotations: { title: "Set the clone source", ...WRITE5, idempotentHint: true },
17718
+ annotations: { title: "Set the clone source", ...WRITE4, idempotentHint: true },
18035
17719
  handler: (args) => {
18036
17720
  if (args.clear === true) {
18037
17721
  if (args.x !== void 0 || args.y !== void 0) throw new LayerOperationError("Give either clear true or x and y, not both.");
@@ -18057,7 +17741,7 @@ function createImageRetouchTools(controller) {
18057
17741
  },
18058
17742
  additionalProperties: false
18059
17743
  },
18060
- annotations: { title: "Transform the clone source", ...WRITE5, idempotentHint: false },
17744
+ annotations: { title: "Transform the clone source", ...WRITE4, idempotentHint: false },
18061
17745
  handler: (args) => {
18062
17746
  if (args.reset === true) {
18063
17747
  if (Object.keys(args).some((k) => k !== "reset")) throw new LayerOperationError("Give either reset true or transform values, not both.");
@@ -18083,8 +17767,8 @@ function pick(args, keys) {
18083
17767
  }
18084
17768
 
18085
17769
  // 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 };
17770
+ var READ6 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17771
+ var DESTRUCTIVE3 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18088
17772
  var DATA = {
18089
17773
  type: "string",
18090
17774
  minLength: 1,
@@ -18104,7 +17788,7 @@ function createImagePsdTools(controller) {
18104
17788
  title: "Inspect a PSD",
18105
17789
  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
17790
  inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
18107
- annotations: { title: "Inspect a PSD", ...READ7 },
17791
+ annotations: { title: "Inspect a PSD", ...READ6 },
18108
17792
  handler: ({ data }) => {
18109
17793
  const res = importPsd(psdBytesFromBase64(data), { skipPixels: true });
18110
17794
  return {
@@ -18122,7 +17806,7 @@ function createImagePsdTools(controller) {
18122
17806
  title: "Open a PSD as the document",
18123
17807
  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
17808
  inputSchema: { type: "object", properties: { data: DATA }, required: ["data"], additionalProperties: false },
18125
- annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE4 },
17809
+ annotations: { title: "Open a PSD as the document", ...DESTRUCTIVE3 },
18126
17810
  handler: ({ data }) => {
18127
17811
  const res = controller.loadPsd(psdBytesFromBase64(data));
18128
17812
  const s = controller.getState();
@@ -18141,7 +17825,7 @@ function createImagePsdTools(controller) {
18141
17825
  title: "Export the document as a PSD",
18142
17826
  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
17827
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
18144
- annotations: { title: "Export the document as a PSD", ...READ7 },
17828
+ annotations: { title: "Export the document as a PSD", ...READ6 },
18145
17829
  handler: async () => {
18146
17830
  const res = await controller.toPsd();
18147
17831
  return {
@@ -18159,8 +17843,8 @@ function createImagePsdTools(controller) {
18159
17843
  }
18160
17844
 
18161
17845
  // 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 };
17846
+ var READ7 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
17847
+ var WRITE5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18164
17848
  var round4 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
18165
17849
  var roundPoint = (p) => ({ x: round4(p.x), y: round4(p.y) });
18166
17850
  var POINT = {
@@ -18259,7 +17943,7 @@ function createImageTransformTools(controller) {
18259
17943
  },
18260
17944
  additionalProperties: false
18261
17945
  },
18262
- annotations: { title: "Get the Free Transform frame", ...READ8 },
17946
+ annotations: { title: "Get the Free Transform frame", ...READ7 },
18263
17947
  handler: (args) => {
18264
17948
  const init = targetFrom(args);
18265
17949
  if (init.content === "selection-copy") init.content = "selection";
@@ -18292,7 +17976,7 @@ function createImageTransformTools(controller) {
18292
17976
  properties: { ...TARGET3, ...GEOMETRY },
18293
17977
  additionalProperties: false
18294
17978
  },
18295
- annotations: { title: "Free Transform a layer", ...WRITE6 },
17979
+ annotations: { title: "Free Transform a layer", ...WRITE5 },
18296
17980
  handler: (args) => summary2(controller.transformLayer({ ...targetFrom(args), ...geometryFrom(args) }))
18297
17981
  };
18298
17982
  const warpLayer = {
@@ -18322,7 +18006,7 @@ function createImageTransformTools(controller) {
18322
18006
  },
18323
18007
  additionalProperties: false
18324
18008
  },
18325
- annotations: { title: "Warp a layer", ...WRITE6 },
18009
+ annotations: { title: "Warp a layer", ...WRITE5 },
18326
18010
  handler: (args) => {
18327
18011
  const hasPreset = ["style", "bend", "horizontal", "vertical", "orientation"].some((k) => args[k] !== void 0);
18328
18012
  if (hasPreset && args.mesh !== void 0) throw new LayerOperationError("Give a preset (style, bend, horizontal, vertical, orientation) or a mesh, not both.");
@@ -18356,7 +18040,7 @@ function createImageTransformTools(controller) {
18356
18040
  properties: { interpolation: { ...TARGET3.interpolation, description: "Resampling of soft edges: nearest, bilinear or bicubic (default)." }, ...GEOMETRY },
18357
18041
  additionalProperties: false
18358
18042
  },
18359
- annotations: { title: "Transform the selection outline", ...WRITE6 },
18043
+ annotations: { title: "Transform the selection outline", ...WRITE5 },
18360
18044
  handler: (args) => {
18361
18045
  const res = controller.transformLayer({ content: "selection-outline", interpolation: args.interpolation, ...geometryFrom(args) });
18362
18046
  return { changed: res.changed, frame: { ...res.box }, corners: res.corners.map(roundPoint), bounds: res.bounds };
@@ -18377,7 +18061,7 @@ function createImageTransformTools(controller) {
18377
18061
  required: ["axis"],
18378
18062
  additionalProperties: false
18379
18063
  },
18380
- annotations: { title: "Flip a layer", ...WRITE6 },
18064
+ annotations: { title: "Flip a layer", ...WRITE5 },
18381
18065
  handler: (args) => summary2(controller.flipLayer(args.axis, targetFrom(args)))
18382
18066
  };
18383
18067
  const rotate90 = {
@@ -18395,20 +18079,20 @@ function createImageTransformTools(controller) {
18395
18079
  required: ["turn"],
18396
18080
  additionalProperties: false
18397
18081
  },
18398
- annotations: { title: "Rotate a layer by quarter turns", ...WRITE6 },
18082
+ annotations: { title: "Rotate a layer by quarter turns", ...WRITE5 },
18399
18083
  handler: (args) => summary2(controller.rotateLayer90(args.turn, targetFrom(args)))
18400
18084
  };
18401
18085
  return [getFrame, transformLayer, warpLayer, transformSelection, flipLayer, rotate90];
18402
18086
  }
18403
18087
 
18404
18088
  // 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 };
18089
+ var READ8 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18090
+ var WRITE6 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18091
+ var WRITE_IDEMPOTENT3 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18092
+ var DESTRUCTIVE4 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18409
18093
  var round5 = (n, digits = 3) => Math.round(n * 10 ** digits) / 10 ** digits;
18410
18094
  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)." };
18095
+ var LAYER_ID3 = { type: "string", description: "Smart object layer id from list_layers (type smart)." };
18412
18096
  var FILTER_ID = { type: "string", description: "Smart filter id from get_smart_object or add_smart_filter." };
18413
18097
  var POINT2 = {
18414
18098
  type: "object",
@@ -18460,8 +18144,8 @@ function createImageSmartObjectTools(controller) {
18460
18144
  name: "get_smart_object",
18461
18145
  title: "Read a smart object",
18462
18146
  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 },
18147
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18148
+ annotations: { title: "Read a smart object", ...READ8 },
18465
18149
  handler: ({ layerId }) => info(smartId(layerId))
18466
18150
  };
18467
18151
  const convert = {
@@ -18476,7 +18160,7 @@ function createImageSmartObjectTools(controller) {
18476
18160
  },
18477
18161
  additionalProperties: false
18478
18162
  },
18479
- annotations: { title: "Convert to Smart Object", ...WRITE7 },
18163
+ annotations: { title: "Convert to Smart Object", ...WRITE6 },
18480
18164
  handler: ({ layerIds, name }) => {
18481
18165
  for (const id2 of layerIds ?? []) requireLayer(controller.getLayers(), id2);
18482
18166
  const id = controller.convertToSmartObject(layerIds, { name });
@@ -18487,8 +18171,8 @@ function createImageSmartObjectTools(controller) {
18487
18171
  name: "rasterize_smart_object",
18488
18172
  title: "Rasterize a smart object",
18489
18173
  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 },
18174
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18175
+ annotations: { title: "Rasterize a smart object", ...DESTRUCTIVE4 },
18492
18176
  handler: ({ layerId }) => ({ layer: layerSummary(controller.rasterizeSmartObject(smartId(layerId))) })
18493
18177
  };
18494
18178
  const setTransform = {
@@ -18498,7 +18182,7 @@ function createImageSmartObjectTools(controller) {
18498
18182
  inputSchema: {
18499
18183
  type: "object",
18500
18184
  properties: {
18501
- layerId: LAYER_ID4,
18185
+ layerId: LAYER_ID3,
18502
18186
  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
18187
  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
18188
  scaleX: { type: "number", description: "Width in percent of the contents\u2019 own width (negative flips)." },
@@ -18541,7 +18225,7 @@ function createImageSmartObjectTools(controller) {
18541
18225
  required: ["layerId"],
18542
18226
  additionalProperties: false
18543
18227
  },
18544
- annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT4 },
18228
+ annotations: { title: "Set a smart object\u2019s transform", ...WRITE_IDEMPOTENT3 },
18545
18229
  handler: (args) => {
18546
18230
  const id = smartId(args.layerId);
18547
18231
  let warp;
@@ -18580,22 +18264,22 @@ function createImageSmartObjectTools(controller) {
18580
18264
  inputSchema: {
18581
18265
  type: "object",
18582
18266
  properties: {
18583
- layerId: LAYER_ID4,
18267
+ layerId: LAYER_ID3,
18584
18268
  image: { type: "string", description: "The new contents: a PNG as a data URL or base64 (other formats and URLs need a browser)." },
18585
18269
  name: { type: "string", description: "File name of the contents (default the old name with .png)." }
18586
18270
  },
18587
18271
  required: ["layerId", "image"],
18588
18272
  additionalProperties: false
18589
18273
  },
18590
- annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE5 },
18274
+ annotations: { title: "Replace a smart object\u2019s contents", ...DESTRUCTIVE4 },
18591
18275
  handler: async ({ layerId, image, name }) => controller.replaceSmartObjectContentsFromImage(smartId(layerId), imageArg(image), name)
18592
18276
  };
18593
18277
  const exportContents = {
18594
18278
  name: "export_smart_object_contents",
18595
18279
  title: "Export a smart object\u2019s contents",
18596
18280
  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 },
18281
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18282
+ annotations: { title: "Export a smart object\u2019s contents", ...READ8 },
18599
18283
  handler: ({ layerId }) => {
18600
18284
  const f = controller.exportSmartObjectContents(smartId(layerId));
18601
18285
  return { name: f.name, mimeType: f.mimeType, byteLength: f.bytes.length, base64: bytesToBase64(f.bytes) };
@@ -18608,14 +18292,14 @@ function createImageSmartObjectTools(controller) {
18608
18292
  inputSchema: {
18609
18293
  type: "object",
18610
18294
  properties: {
18611
- layerId: LAYER_ID4,
18295
+ layerId: LAYER_ID3,
18612
18296
  linked: { type: "boolean", description: "true shares the contents with the original; false (default) makes independent contents." },
18613
18297
  name: { type: "string", description: 'Name of the copy (default "<name> copy").' }
18614
18298
  },
18615
18299
  required: ["layerId"],
18616
18300
  additionalProperties: false
18617
18301
  },
18618
- annotations: { title: "Copy a smart object", ...WRITE7 },
18302
+ annotations: { title: "Copy a smart object", ...WRITE6 },
18619
18303
  handler: ({ layerId, linked, name }) => {
18620
18304
  const id = controller.copySmartObject(smartId(layerId), linked === true, name);
18621
18305
  return { layer: layerSummary(id), contentsId: controller.getSmartObject(id).contents.id };
@@ -18625,8 +18309,8 @@ function createImageSmartObjectTools(controller) {
18625
18309
  name: "edit_smart_object_contents",
18626
18310
  title: "Edit a smart object\u2019s contents",
18627
18311
  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 },
18312
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3 }, required: ["layerId"], additionalProperties: false },
18313
+ annotations: { title: "Edit a smart object\u2019s contents", ...WRITE6 },
18630
18314
  handler: ({ layerId }) => {
18631
18315
  const res = controller.editSmartObjectContents(smartId(layerId));
18632
18316
  const s = controller.getState();
@@ -18642,7 +18326,7 @@ function createImageSmartObjectTools(controller) {
18642
18326
  properties: { save: { type: "boolean", description: "true (default) saves the edits into the smart object; false discards them." } },
18643
18327
  additionalProperties: false
18644
18328
  },
18645
- annotations: { title: "Close a smart object\u2019s contents", ...WRITE7 },
18329
+ annotations: { title: "Close a smart object\u2019s contents", ...WRITE6 },
18646
18330
  handler: ({ save }) => ({ ...controller.closeSmartObjectContents(save !== false), editing: controller.getEditingContents() })
18647
18331
  };
18648
18332
  const addFilter = {
@@ -18652,7 +18336,7 @@ function createImageSmartObjectTools(controller) {
18652
18336
  inputSchema: {
18653
18337
  type: "object",
18654
18338
  properties: {
18655
- layerId: LAYER_ID4,
18339
+ layerId: LAYER_ID3,
18656
18340
  kind: { type: "string", enum: ["develop", "blur"], description: "Filter kind." },
18657
18341
  index: { type: "integer", minimum: 0, description: "Position in the stack, 0 = bottom, applied first (default the top)." },
18658
18342
  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 +18345,7 @@ function createImageSmartObjectTools(controller) {
18661
18345
  required: ["layerId", "kind"],
18662
18346
  additionalProperties: false
18663
18347
  },
18664
- annotations: { title: "Add a smart filter", ...WRITE7 },
18348
+ annotations: { title: "Add a smart filter", ...WRITE6 },
18665
18349
  handler: (args) => {
18666
18350
  const id = smartId(args.layerId);
18667
18351
  const masked = args.useSelection !== false && controller.hasSelection;
@@ -18675,11 +18359,11 @@ function createImageSmartObjectTools(controller) {
18675
18359
  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
18360
  inputSchema: {
18677
18361
  type: "object",
18678
- properties: { layerId: LAYER_ID4, filterId: FILTER_ID, ...FILTER_SETTINGS },
18362
+ properties: { layerId: LAYER_ID3, filterId: FILTER_ID, ...FILTER_SETTINGS },
18679
18363
  required: ["layerId", "filterId"],
18680
18364
  additionalProperties: false
18681
18365
  },
18682
- annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT4 },
18366
+ annotations: { title: "Change a smart filter", ...WRITE_IDEMPOTENT3 },
18683
18367
  handler: (args) => {
18684
18368
  const id = smartId(args.layerId);
18685
18369
  const changes = settingsFrom(args);
@@ -18692,8 +18376,8 @@ function createImageSmartObjectTools(controller) {
18692
18376
  name: "remove_smart_filter",
18693
18377
  title: "Remove a smart filter",
18694
18378
  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 },
18379
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID3, filterId: FILTER_ID }, required: ["layerId", "filterId"], additionalProperties: false },
18380
+ annotations: { title: "Remove a smart filter", ...DESTRUCTIVE4 },
18697
18381
  handler: ({ layerId, filterId }) => {
18698
18382
  const id = smartId(layerId);
18699
18383
  controller.removeSmartFilter(id, filterId);
@@ -18706,11 +18390,11 @@ function createImageSmartObjectTools(controller) {
18706
18390
  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
18391
  inputSchema: {
18708
18392
  type: "object",
18709
- properties: { layerId: LAYER_ID4, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
18393
+ properties: { layerId: LAYER_ID3, filterId: FILTER_ID, index: { type: "integer", minimum: 0, description: "New position, 0 = bottom (applied first)." } },
18710
18394
  required: ["layerId", "filterId", "index"],
18711
18395
  additionalProperties: false
18712
18396
  },
18713
- annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT4 },
18397
+ annotations: { title: "Reorder a smart filter", ...WRITE_IDEMPOTENT3 },
18714
18398
  handler: ({ layerId, filterId, index }) => {
18715
18399
  const id = smartId(layerId);
18716
18400
  controller.moveSmartFilter(id, filterId, index);
@@ -18723,11 +18407,11 @@ function createImageSmartObjectTools(controller) {
18723
18407
  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
18408
  inputSchema: {
18725
18409
  type: "object",
18726
- properties: { layerId: LAYER_ID4, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
18410
+ properties: { layerId: LAYER_ID3, enabled: { type: "boolean", description: "false hides every smart filter; true shows them again." } },
18727
18411
  required: ["layerId", "enabled"],
18728
18412
  additionalProperties: false
18729
18413
  },
18730
- annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT4 },
18414
+ annotations: { title: "Turn smart filters on or off", ...WRITE_IDEMPOTENT3 },
18731
18415
  handler: ({ layerId, enabled }) => {
18732
18416
  const id = smartId(layerId);
18733
18417
  controller.setSmartFiltersEnabled(id, enabled === true);
@@ -18741,7 +18425,7 @@ function createImageSmartObjectTools(controller) {
18741
18425
  inputSchema: {
18742
18426
  type: "object",
18743
18427
  properties: {
18744
- layerId: LAYER_ID4,
18428
+ layerId: LAYER_ID3,
18745
18429
  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
18430
  density: { type: "number", minimum: 0, maximum: 1, description: "How much hidden areas hide, 0..1 (default 1)." },
18747
18431
  feather: { type: "number", minimum: 0, maximum: 1e3, description: "Gaussian softening in px (default 0)." },
@@ -18751,7 +18435,7 @@ function createImageSmartObjectTools(controller) {
18751
18435
  required: ["layerId", "from"],
18752
18436
  additionalProperties: false
18753
18437
  },
18754
- annotations: { title: "Set the smart filter mask", ...WRITE7 },
18438
+ annotations: { title: "Set the smart filter mask", ...WRITE6 },
18755
18439
  handler: (args) => {
18756
18440
  const id = smartId(args.layerId);
18757
18441
  const props = {};
@@ -18764,11 +18448,11 @@ function createImageSmartObjectTools(controller) {
18764
18448
  }
18765
18449
 
18766
18450
  // 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." };
18451
+ var READ9 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18452
+ var WRITE7 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
18453
+ var WRITE_IDEMPOTENT4 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
18454
+ var DESTRUCTIVE5 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
18455
+ var LAYER_ID4 = { type: "string", description: "Shape layer id from list_layers (type shape) or add_shape_layer." };
18772
18456
  var COMPONENT_INDEX = { type: "integer", minimum: 0, description: "Component index from get_shape_layer (0 = bottom component)." };
18773
18457
  var OP = {
18774
18458
  type: "string",
@@ -18790,7 +18474,7 @@ var BOX = {
18790
18474
  height: NUM("Height in pixels."),
18791
18475
  transform: { $ref: "#/$defs/matrix" }
18792
18476
  };
18793
- var DEFS2 = {
18477
+ var DEFS = {
18794
18478
  matrix: MATRIX,
18795
18479
  point: {
18796
18480
  type: "object",
@@ -19017,8 +18701,8 @@ function createImageShapeTools(controller) {
19017
18701
  name: "get_shape_layer",
19018
18702
  title: "Read a shape layer",
19019
18703
  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 },
18704
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18705
+ annotations: { title: "Read a shape layer", ...READ9 },
19022
18706
  handler: ({ layerId }) => controller.getShapeLayer(shapeId(layerId))
19023
18707
  };
19024
18708
  const add2 = {
@@ -19027,7 +18711,7 @@ function createImageShapeTools(controller) {
19027
18711
  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
18712
  inputSchema: {
19029
18713
  type: "object",
19030
- $defs: DEFS2,
18714
+ $defs: DEFS,
19031
18715
  properties: {
19032
18716
  ...GEOMETRY2,
19033
18717
  components: {
@@ -19049,7 +18733,7 @@ function createImageShapeTools(controller) {
19049
18733
  },
19050
18734
  additionalProperties: false
19051
18735
  },
19052
- annotations: { title: "Add a shape layer", ...WRITE8 },
18736
+ annotations: { title: "Add a shape layer", ...WRITE7 },
19053
18737
  handler: (args) => {
19054
18738
  const init = { ...geometry(args) };
19055
18739
  if (args.components !== void 0) init.components = args.components.map(geometry);
@@ -19067,9 +18751,9 @@ function createImageShapeTools(controller) {
19067
18751
  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
18752
  inputSchema: {
19069
18753
  type: "object",
19070
- $defs: DEFS2,
18754
+ $defs: DEFS,
19071
18755
  properties: {
19072
- layerId: LAYER_ID5,
18756
+ layerId: LAYER_ID4,
19073
18757
  fill: { anyOf: [{ $ref: "#/$defs/paint" }, { type: "null", description: "No fill." }], description: "New fill paint, or null for none." },
19074
18758
  stroke: { anyOf: [{ $ref: "#/$defs/stroke" }, { type: "null", description: "No stroke." }], description: "Stroke settings to change, or null to remove the stroke." },
19075
18759
  fillRule: { type: "string", enum: ["nonzero", "evenodd"], description: "Winding rule within a component." }
@@ -19077,7 +18761,7 @@ function createImageShapeTools(controller) {
19077
18761
  required: ["layerId"],
19078
18762
  additionalProperties: false
19079
18763
  },
19080
- annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT5 },
18764
+ annotations: { title: "Restyle a shape", ...WRITE_IDEMPOTENT4 },
19081
18765
  handler: ({ layerId, fill, stroke, fillRule }) => {
19082
18766
  const id = shapeId(layerId);
19083
18767
  if (fill === void 0 && stroke === void 0 && fillRule === void 0) throw new LayerOperationError("Give fill, stroke or fillRule to change.");
@@ -19090,9 +18774,9 @@ function createImageShapeTools(controller) {
19090
18774
  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
18775
  inputSchema: {
19092
18776
  type: "object",
19093
- $defs: DEFS2,
18777
+ $defs: DEFS,
19094
18778
  properties: {
19095
- layerId: LAYER_ID5,
18779
+ layerId: LAYER_ID4,
19096
18780
  componentIndex: COMPONENT_INDEX,
19097
18781
  shape: {
19098
18782
  type: "object",
@@ -19125,7 +18809,7 @@ function createImageShapeTools(controller) {
19125
18809
  required: ["layerId", "componentIndex"],
19126
18810
  additionalProperties: false
19127
18811
  },
19128
- annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT5 },
18812
+ annotations: { title: "Edit a shape component", ...WRITE_IDEMPOTENT4 },
19129
18813
  handler: ({ layerId, componentIndex, ...rest }) => {
19130
18814
  const id = shapeId(layerId);
19131
18815
  const change = geometry(rest);
@@ -19139,28 +18823,28 @@ function createImageShapeTools(controller) {
19139
18823
  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
18824
  inputSchema: {
19141
18825
  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)." } },
18826
+ $defs: DEFS,
18827
+ properties: { layerId: LAYER_ID4, ...GEOMETRY2, op: OP, index: { type: "integer", minimum: 0, description: "Position among the components, 0 = bottom (default the top)." } },
19144
18828
  required: ["layerId"],
19145
18829
  additionalProperties: false
19146
18830
  },
19147
- annotations: { title: "Add a shape component", ...WRITE8 },
18831
+ annotations: { title: "Add a shape component", ...WRITE7 },
19148
18832
  handler: ({ layerId, index, ...rest }) => controller.addShapeComponent(shapeId(layerId), geometry(rest), index)
19149
18833
  };
19150
18834
  const removeComponent = {
19151
18835
  name: "remove_shape_component",
19152
18836
  title: "Delete a shape component",
19153
18837
  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 },
18838
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4, componentIndex: COMPONENT_INDEX }, required: ["layerId", "componentIndex"], additionalProperties: false },
18839
+ annotations: { title: "Delete a shape component", ...DESTRUCTIVE5 },
19156
18840
  handler: ({ layerId, componentIndex }) => controller.removeShapeComponent(shapeId(layerId), componentIndex)
19157
18841
  };
19158
18842
  const merge = {
19159
18843
  name: "merge_shape_components",
19160
18844
  title: "Merge shape components",
19161
18845
  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 },
18846
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID4 }, required: ["layerId"], additionalProperties: false },
18847
+ annotations: { title: "Merge shape components", ...DESTRUCTIVE5 },
19164
18848
  handler: ({ layerId }) => controller.mergeShapeComponents(shapeId(layerId))
19165
18849
  };
19166
18850
  const layerArg = (v) => {
@@ -19214,7 +18898,7 @@ function createImageShapeTools(controller) {
19214
18898
  title: "Make a path from the selection",
19215
18899
  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
18900
  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 },
18901
+ annotations: { title: "Make a path from the selection", ...READ9 },
19218
18902
  handler: (args) => {
19219
18903
  const out = controller.selectionToPath(traceOptions(args));
19220
18904
  const { subpaths, ...rest } = out;
@@ -19227,7 +18911,7 @@ function createImageShapeTools(controller) {
19227
18911
  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
18912
  inputSchema: {
19229
18913
  type: "object",
19230
- $defs: DEFS2,
18914
+ $defs: DEFS,
19231
18915
  properties: {
19232
18916
  pathId: { ...PATH_ID, description: "A document path from list_paths, instead of shape / subpaths / components." },
19233
18917
  ...PATH_PROPS,
@@ -19237,7 +18921,7 @@ function createImageShapeTools(controller) {
19237
18921
  },
19238
18922
  additionalProperties: false
19239
18923
  },
19240
- annotations: { title: "Make a selection from a path", ...WRITE8 },
18924
+ annotations: { title: "Make a selection from a path", ...WRITE7 },
19241
18925
  handler: (args) => {
19242
18926
  const mode = args.mode;
19243
18927
  controller.pathToSelection(fromPathId(args) ?? pathSpec(args), { feather: args.feather, antiAlias: args.antiAlias, mode });
@@ -19250,7 +18934,7 @@ function createImageShapeTools(controller) {
19250
18934
  title: "Read a vector mask",
19251
18935
  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
18936
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19253
- annotations: { title: "Read a vector mask", ...READ10 },
18937
+ annotations: { title: "Read a vector mask", ...READ9 },
19254
18938
  handler: ({ layerId }) => ({ vectorMask: controller.getVectorMask(layerArg(layerId)) })
19255
18939
  };
19256
18940
  const addVectorMask = {
@@ -19259,7 +18943,7 @@ function createImageShapeTools(controller) {
19259
18943
  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
18944
  inputSchema: {
19261
18945
  type: "object",
19262
- $defs: DEFS2,
18946
+ $defs: DEFS,
19263
18947
  properties: {
19264
18948
  layerId: LAYER,
19265
18949
  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 +18954,7 @@ function createImageShapeTools(controller) {
19270
18954
  required: ["layerId"],
19271
18955
  additionalProperties: false
19272
18956
  },
19273
- annotations: { title: "Add a vector mask", ...WRITE8 },
18957
+ annotations: { title: "Add a vector mask", ...WRITE7 },
19274
18958
  handler: (args) => {
19275
18959
  const id = layerArg(args.layerId);
19276
18960
  const spec = fromPathId(args) ?? pathSpec(args);
@@ -19285,8 +18969,8 @@ function createImageShapeTools(controller) {
19285
18969
  name: "set_vector_mask_path",
19286
18970
  title: "Replace a vector mask path",
19287
18971
  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 },
18972
+ inputSchema: { type: "object", $defs: DEFS, properties: { layerId: LAYER, ...PATH_PROPS }, required: ["layerId"], additionalProperties: false },
18973
+ annotations: { title: "Replace a vector mask path", ...WRITE_IDEMPOTENT4 },
19290
18974
  handler: (args) => {
19291
18975
  const id = layerArg(args.layerId);
19292
18976
  controller.setVectorMaskPath(id, pathSpec(args));
@@ -19310,7 +18994,7 @@ function createImageShapeTools(controller) {
19310
18994
  required: ["layerId"],
19311
18995
  additionalProperties: false
19312
18996
  },
19313
- annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT5 },
18997
+ annotations: { title: "Set vector mask properties", ...WRITE_IDEMPOTENT4 },
19314
18998
  handler: ({ layerId, ...props }) => {
19315
18999
  const id = layerArg(layerId);
19316
19000
  controller.setVectorMaskProps(id, props);
@@ -19336,7 +19020,7 @@ function createImageShapeTools(controller) {
19336
19020
  required: ["layerId", "component", "subpath", "segment", "mode"],
19337
19021
  additionalProperties: false
19338
19022
  },
19339
- annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT5 },
19023
+ annotations: { title: "Set a vector mask segment's edge", ...WRITE_IDEMPOTENT4 },
19340
19024
  handler: ({ layerId, component, subpath, segment, mode, radius, inner, outer }) => {
19341
19025
  const id = layerArg(layerId);
19342
19026
  const vectorMask = controller.setVectorMaskEdge(
@@ -19353,7 +19037,7 @@ function createImageShapeTools(controller) {
19353
19037
  title: "Rasterize a vector mask",
19354
19038
  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
19039
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19356
- annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE6 },
19040
+ annotations: { title: "Rasterize a vector mask", ...DESTRUCTIVE5 },
19357
19041
  handler: ({ layerId }) => {
19358
19042
  const id = layerArg(layerId);
19359
19043
  const mask = controller.rasterizeVectorMask(id);
@@ -19365,7 +19049,7 @@ function createImageShapeTools(controller) {
19365
19049
  title: "Delete a vector mask",
19366
19050
  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
19051
  inputSchema: { type: "object", properties: { layerId: LAYER }, required: ["layerId"], additionalProperties: false },
19368
- annotations: { title: "Delete a vector mask", ...DESTRUCTIVE6 },
19052
+ annotations: { title: "Delete a vector mask", ...DESTRUCTIVE5 },
19369
19053
  handler: ({ layerId }) => {
19370
19054
  const id = layerArg(layerId);
19371
19055
  controller.removeVectorMask(id);
@@ -19377,15 +19061,15 @@ function createImageShapeTools(controller) {
19377
19061
  title: "List document paths",
19378
19062
  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
19063
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
19380
- annotations: { title: "List document paths", ...READ10 },
19064
+ annotations: { title: "List document paths", ...READ9 },
19381
19065
  handler: () => ({ paths: controller.getPaths().map((p) => pathSummary(p.id)), activePathId: controller.getState().activePathId ?? null })
19382
19066
  };
19383
- const getPath2 = {
19067
+ const getPath = {
19384
19068
  name: "get_path",
19385
19069
  title: "Read a document path",
19386
19070
  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
19071
  inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
19388
- annotations: { title: "Read a document path", ...READ10 },
19072
+ annotations: { title: "Read a document path", ...READ9 },
19389
19073
  handler: ({ pathId }) => {
19390
19074
  const p = controller.getPath(String(pathId));
19391
19075
  if (!p) throw new Error(`No path "${String(pathId)}". Call list_paths for ids.`);
@@ -19397,7 +19081,7 @@ function createImageShapeTools(controller) {
19397
19081
  title: "Make a work path from the selection",
19398
19082
  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
19083
  inputSchema: { type: "object", properties: { ...TRACE_PROPS }, additionalProperties: false },
19400
- annotations: { title: "Make a work path from the selection", ...WRITE8 },
19084
+ annotations: { title: "Make a work path from the selection", ...WRITE7 },
19401
19085
  handler: (args) => ({ path: pathSummary(controller.makeWorkPath(traceOptions(args)).id) })
19402
19086
  };
19403
19087
  const addPath = {
@@ -19406,11 +19090,11 @@ function createImageShapeTools(controller) {
19406
19090
  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
19091
  inputSchema: {
19408
19092
  type: "object",
19409
- $defs: DEFS2,
19093
+ $defs: DEFS,
19410
19094
  properties: { name: { type: "string", description: 'The path name (default "Path n").' }, ...PATH_PROPS },
19411
19095
  additionalProperties: false
19412
19096
  },
19413
- annotations: { title: "Add a document path", ...WRITE8 },
19097
+ annotations: { title: "Add a document path", ...WRITE7 },
19414
19098
  handler: (args) => {
19415
19099
  const spec = pathSpec(args);
19416
19100
  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 +19105,8 @@ function createImageShapeTools(controller) {
19421
19105
  name: "set_path_geometry",
19422
19106
  title: "Replace a document path",
19423
19107
  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 },
19108
+ inputSchema: { type: "object", $defs: DEFS, properties: { pathId: PATH_ID, ...PATH_PROPS }, required: ["pathId"], additionalProperties: false },
19109
+ annotations: { title: "Replace a document path", ...WRITE_IDEMPOTENT4 },
19426
19110
  handler: (args) => ({ path: pathSummary(controller.setPathGeometry(String(args.pathId), pathSpec(args)).id) })
19427
19111
  };
19428
19112
  const renamePath = {
@@ -19430,7 +19114,7 @@ function createImageShapeTools(controller) {
19430
19114
  title: "Rename or save a path",
19431
19115
  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
19116
  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 },
19117
+ annotations: { title: "Rename or save a path", ...WRITE_IDEMPOTENT4 },
19434
19118
  handler: ({ pathId, name }) => ({ path: pathSummary(controller.renamePath(String(pathId), String(name)).id) })
19435
19119
  };
19436
19120
  const duplicatePath = {
@@ -19438,7 +19122,7 @@ function createImageShapeTools(controller) {
19438
19122
  title: "Duplicate a path",
19439
19123
  description: 'Duplicates a document path as a saved path (default name "<name> copy"). One undo step. Returns the new path.',
19440
19124
  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 },
19125
+ annotations: { title: "Duplicate a path", ...WRITE7 },
19442
19126
  handler: ({ pathId, name }) => ({ path: pathSummary(controller.duplicatePath(String(pathId), name).id) })
19443
19127
  };
19444
19128
  const deletePath = {
@@ -19446,7 +19130,7 @@ function createImageShapeTools(controller) {
19446
19130
  title: "Delete a path",
19447
19131
  description: "Deletes a document path (undo_image brings it back). Returns the remaining paths.",
19448
19132
  inputSchema: { type: "object", properties: { pathId: PATH_ID }, required: ["pathId"], additionalProperties: false },
19449
- annotations: { title: "Delete a path", ...DESTRUCTIVE6 },
19133
+ annotations: { title: "Delete a path", ...DESTRUCTIVE5 },
19450
19134
  handler: ({ pathId }) => {
19451
19135
  controller.deletePath(String(pathId));
19452
19136
  return { paths: controller.getPaths().map((p) => pathSummary(p.id)) };
@@ -19462,7 +19146,7 @@ function createImageShapeTools(controller) {
19462
19146
  title: "Fill a path",
19463
19147
  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
19148
  inputSchema: { type: "object", properties: { pathId: PATH_ID, ...PAINT_PROPS }, required: ["pathId"], additionalProperties: false },
19465
- annotations: { title: "Fill a path", ...WRITE8 },
19149
+ annotations: { title: "Fill a path", ...WRITE7 },
19466
19150
  handler: (args) => controller.fillPath(String(args.pathId), { layerId: args.layerId, color: args.color, opacity: args.opacity })
19467
19151
  };
19468
19152
  const strokePath = {
@@ -19475,7 +19159,7 @@ function createImageShapeTools(controller) {
19475
19159
  required: ["pathId", "width"],
19476
19160
  additionalProperties: false
19477
19161
  },
19478
- annotations: { title: "Stroke a path", ...WRITE8 },
19162
+ annotations: { title: "Stroke a path", ...WRITE7 },
19479
19163
  handler: (args) => controller.strokePath(String(args.pathId), { width: args.width, layerId: args.layerId, color: args.color, opacity: args.opacity })
19480
19164
  };
19481
19165
  return [
@@ -19496,7 +19180,7 @@ function createImageShapeTools(controller) {
19496
19180
  selectionToPath,
19497
19181
  pathToSelection2,
19498
19182
  listPaths,
19499
- getPath2,
19183
+ getPath,
19500
19184
  makeWorkPath,
19501
19185
  addPath,
19502
19186
  setPathGeometry,
@@ -19509,11 +19193,11 @@ function createImageShapeTools(controller) {
19509
19193
  }
19510
19194
 
19511
19195
  // 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." };
19196
+ var READ10 = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19197
+ var WRITE8 = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
19198
+ var WRITE_IDEMPOTENT5 = { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false };
19199
+ var DESTRUCTIVE6 = { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: false };
19200
+ var LAYER_ID5 = { type: "string", description: "Type layer id from list_layers (type type) or add_text_layer." };
19517
19201
  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
19202
  var END = { type: "integer", minimum: 0, description: "End of the range, exclusive (default the end of the text)." };
19519
19203
  var STYLE = {
@@ -19566,15 +19250,15 @@ function createImageTypeTools(controller) {
19566
19250
  title: "List fonts",
19567
19251
  description: "Returns the font families type layers can use here (generic families such as sans-serif always work). Changes nothing.",
19568
19252
  inputSchema: { type: "object", properties: {}, additionalProperties: false },
19569
- annotations: { title: "List fonts", ...READ11 },
19253
+ annotations: { title: "List fonts", ...READ10 },
19570
19254
  handler: () => ({ families: controller.listFonts(), shaper: controller.getTextShaper()?.id ?? null })
19571
19255
  };
19572
19256
  const get = {
19573
19257
  name: "get_text_layer",
19574
19258
  title: "Read a type layer",
19575
19259
  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 },
19260
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19261
+ annotations: { title: "Read a type layer", ...READ10 },
19578
19262
  handler: ({ layerId }) => controller.getTextLayer(typeId(layerId))
19579
19263
  };
19580
19264
  const add2 = {
@@ -19609,7 +19293,7 @@ function createImageTypeTools(controller) {
19609
19293
  required: ["text", "x", "y"],
19610
19294
  additionalProperties: false
19611
19295
  },
19612
- annotations: { title: "Add a type layer", ...WRITE9 },
19296
+ annotations: { title: "Add a type layer", ...WRITE8 },
19613
19297
  handler: (args) => {
19614
19298
  const init = pick2(args, ["text", "x", "y", "box", "style", "paragraph", "orientation", "rotation", "name", "opacity", "blend", "aboveId", "belowId", "parentId", "index"]);
19615
19299
  if (init.blend !== void 0) init.blend = init.blend;
@@ -19621,16 +19305,16 @@ function createImageTypeTools(controller) {
19621
19305
  name: "set_text",
19622
19306
  title: "Edit text",
19623
19307
  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 },
19308
+ 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 },
19309
+ annotations: { title: "Edit text", ...WRITE8 },
19626
19310
  handler: (args) => controller.setText(typeId(args.layerId), args.text, range(args))
19627
19311
  };
19628
19312
  const setStyle = {
19629
19313
  name: "set_text_style",
19630
19314
  title: "Style a range of text",
19631
19315
  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 },
19316
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...STYLE }, required: ["layerId"], additionalProperties: false },
19317
+ annotations: { title: "Style a range of text", ...WRITE_IDEMPOTENT5 },
19634
19318
  handler: (args) => {
19635
19319
  const style = pick2(args, Object.keys(STYLE));
19636
19320
  if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one style field: ${Object.keys(STYLE).join(", ")}.`);
@@ -19641,8 +19325,8 @@ function createImageTypeTools(controller) {
19641
19325
  name: "set_paragraph_style",
19642
19326
  title: "Style paragraphs",
19643
19327
  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 },
19328
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, start: START, end: END, ...PARAGRAPH }, required: ["layerId"], additionalProperties: false },
19329
+ annotations: { title: "Style paragraphs", ...WRITE_IDEMPOTENT5 },
19646
19330
  handler: (args) => {
19647
19331
  const style = pick2(args, Object.keys(PARAGRAPH));
19648
19332
  if (!Object.keys(style).length) throw new LayerOperationError(`Give at least one paragraph field: ${Object.keys(PARAGRAPH).join(", ")}.`);
@@ -19656,7 +19340,7 @@ function createImageTypeTools(controller) {
19656
19340
  inputSchema: {
19657
19341
  type: "object",
19658
19342
  properties: {
19659
- layerId: LAYER_ID6,
19343
+ layerId: LAYER_ID5,
19660
19344
  kind: { type: "string", enum: ["point", "box"], description: "point or box." },
19661
19345
  width: { type: "number", minimum: 1, description: "Box width in pixels (kind box)." },
19662
19346
  height: { type: "number", minimum: 1, description: "Box height in pixels (kind box)." }
@@ -19664,7 +19348,7 @@ function createImageTypeTools(controller) {
19664
19348
  required: ["layerId", "kind"],
19665
19349
  additionalProperties: false
19666
19350
  },
19667
- annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT6 },
19351
+ annotations: { title: "Point or paragraph text", ...WRITE_IDEMPOTENT5 },
19668
19352
  handler: ({ layerId, kind, width, height }) => {
19669
19353
  const id = typeId(layerId);
19670
19354
  if (kind === "box" && (width === void 0 || height === void 0)) throw new LayerOperationError("kind box needs width and height in pixels.");
@@ -19675,16 +19359,16 @@ function createImageTypeTools(controller) {
19675
19359
  name: "set_text_orientation",
19676
19360
  title: "Horizontal or vertical type",
19677
19361
  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 },
19362
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5, orientation: { ...ORIENTATION, description: "horizontal or vertical." } }, required: ["layerId", "orientation"], additionalProperties: false },
19363
+ annotations: { title: "Horizontal or vertical type", ...WRITE_IDEMPOTENT5 },
19680
19364
  handler: ({ layerId, orientation }) => controller.setTextOrientation(typeId(layerId), orientation)
19681
19365
  };
19682
19366
  const toShape = {
19683
19367
  name: "convert_text_to_shape",
19684
19368
  title: "Convert text to a shape",
19685
19369
  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 },
19370
+ inputSchema: { type: "object", properties: { layerId: LAYER_ID5 }, required: ["layerId"], additionalProperties: false },
19371
+ annotations: { title: "Convert text to a shape", ...DESTRUCTIVE6 },
19688
19372
  handler: ({ layerId }) => {
19689
19373
  const { layerId: id, warnings } = controller.convertTextToShape(typeId(layerId));
19690
19374
  return { layer: layerSummary(id), shape: controller.getShapeLayer(id), warnings };
@@ -19718,7 +19402,7 @@ function createImageTypeTools(controller) {
19718
19402
  required: ["text", "x", "y"],
19719
19403
  additionalProperties: false
19720
19404
  },
19721
- annotations: { title: "Select the shape of text", ...WRITE9 },
19405
+ annotations: { title: "Select the shape of text", ...WRITE8 },
19722
19406
  handler: (args) => {
19723
19407
  const init = pick2(args, ["text", "x", "y", "orientation", "box", "style", "paragraph", "rotation", "mode", "feather", "antiAlias"]);
19724
19408
  controller.selectTextShape(init);
@@ -20231,12 +19915,12 @@ var SelectAndMaskSession = class {
20231
19915
  this.recompute();
20232
19916
  }
20233
19917
  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);
19918
+ const px = this.pixels;
19919
+ if (!px) return;
19920
+ const s = this.settingsValue.highQuality ? 1 : Math.min(1, PREVIEW_SIZE / Math.max(px.width, px.height));
19921
+ const w = Math.max(1, Math.round(px.width * s));
19922
+ const h = Math.max(1, Math.round(px.height * s));
19923
+ this.previewPixels = scalePixels(px, w, h);
20240
19924
  this.belowPreview = this.below ? scalePixels(this.below, w, h) : null;
20241
19925
  this.baseMask = this.base?.bounds ? s === 1 ? this.base : resizeSelection(this.base, w, h) : null;
20242
19926
  }
@@ -20245,8 +19929,8 @@ var SelectAndMaskSession = class {
20245
19929
  * the page, or in the worker, where one job runs at a time and the newest state follows it.
20246
19930
  */
20247
19931
  recompute() {
20248
- const px2 = this.previewPixels;
20249
- if (!px2) return;
19932
+ const px = this.previewPixels;
19933
+ if (!px) return;
20250
19934
  this.note = this.settingsValue.refineMode === "object" ? "Object aware refinement asks the segmentation model on OK; the preview refines by colour." : null;
20251
19935
  if (this.controller.hasSelectionWorker) {
20252
19936
  void this.recomputeInWorker();
@@ -20255,8 +19939,8 @@ var SelectAndMaskSession = class {
20255
19939
  const { scale } = this.previewSize;
20256
19940
  const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
20257
19941
  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;
19942
+ const { selection, refineBrush } = applyRefineEdits(px, this.baseMask, edits, px.width, px.height);
19943
+ this.previewMask = selection?.bounds ? refineSelection(px, selection, scaleParams(this.settingsValue.params, scale), refineBrush) : null;
20260
19944
  this.error = null;
20261
19945
  } catch (err) {
20262
19946
  this.previewMask = null;
@@ -20272,13 +19956,13 @@ var SelectAndMaskSession = class {
20272
19956
  this.computing = true;
20273
19957
  do {
20274
19958
  this.dirty = false;
20275
- const px2 = this.previewPixels;
19959
+ const px = this.previewPixels;
20276
19960
  const { scale } = this.previewSize;
20277
19961
  const edits = [...this.editsList, ...this.live ? [this.live] : []].map((e) => scaleEdit(e, scale));
20278
19962
  try {
20279
19963
  const { mask } = await this.controller.runSelectionJob(
20280
19964
  { op: "refine-preview", base: this.baseMask ? serializeMask(this.baseMask) : null, edits, params: scaleParams(this.settingsValue.params, scale) },
20281
- px2
19965
+ px
20282
19966
  );
20283
19967
  this.previewMask = mask.bounds ? mask : null;
20284
19968
  this.error = null;
@@ -20306,9 +19990,9 @@ var SelectAndMaskSession = class {
20306
19990
  }
20307
19991
  /** The preview drawn in the current view mode: RGBA at {@link previewSize}. */
20308
19992
  render() {
20309
- const px2 = this.previewPixels;
20310
- if (!px2) return new Uint8ClampedArray(0);
20311
- const { width: w, height: h } = px2;
19993
+ const px = this.previewPixels;
19994
+ if (!px) return new Uint8ClampedArray(0);
19995
+ const { width: w, height: h } = px;
20312
19996
  const n = w * h;
20313
19997
  const s = this.settingsValue;
20314
19998
  const mask = (s.showOriginal ? this.baseMask : this.previewMask) ?? createSelectionMask(w, h);
@@ -20330,9 +20014,9 @@ var SelectAndMaskSession = class {
20330
20014
  for (let i = 0; i < n; i++) {
20331
20015
  const a = m[i] / 255;
20332
20016
  const p = i * 4;
20333
- const r = px2.data[p];
20334
- const g = px2.data[p + 1];
20335
- const b = px2.data[p + 2];
20017
+ const r = px.data[p];
20018
+ const g = px.data[p + 1];
20019
+ const b = px.data[p + 2];
20336
20020
  let o;
20337
20021
  const x = i % w;
20338
20022
  const y = (i - x) / w;
@@ -20559,8 +20243,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
20559
20243
  const count = bw * bh;
20560
20244
  for (let py = by; py < by + bh; py++) {
20561
20245
  const rowOffset = py * width;
20562
- for (let px2 = bx; px2 < bx + bw; px2++) {
20563
- const idx = (rowOffset + px2) * 4;
20246
+ for (let px = bx; px < bx + bw; px++) {
20247
+ const idx = (rowOffset + px) * 4;
20564
20248
  rSum += data[idx];
20565
20249
  gSum += data[idx + 1];
20566
20250
  bSum += data[idx + 2];
@@ -20573,8 +20257,8 @@ function applyRegionMosaic(imageData, regions2, blockSize = 12) {
20573
20257
  const aAvg = Math.round(aSum / count);
20574
20258
  for (let py = by; py < by + bh; py++) {
20575
20259
  const rowOffset = py * width;
20576
- for (let px2 = bx; px2 < bx + bw; px2++) {
20577
- const idx = (rowOffset + px2) * 4;
20260
+ for (let px = bx; px < bx + bw; px++) {
20261
+ const idx = (rowOffset + px) * 4;
20578
20262
  data[idx] = rAvg;
20579
20263
  data[idx + 1] = gAvg;
20580
20264
  data[idx + 2] = bAvg;
@@ -21074,179 +20758,6 @@ function layerPanels(layer, options = {}) {
21074
20758
  return panels;
21075
20759
  }
21076
20760
 
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
20761
  // src/image-editor/layers/color-ui.ts
21251
20762
  var WORKING_SPACE_OPTIONS = BUILTIN_PROFILES.filter((b) => b.colorSpace === "rgb").map((b) => ({ id: b.id, label: b.description }));
21252
20763
  var PROOF_PROFILE_OPTIONS = BUILTIN_PROFILES.map((b) => ({ id: b.id, label: b.description }));
@@ -22846,10 +22357,10 @@ var ContentAwareFillSession = class _ContentAwareFillSession {
22846
22357
  const len2 = dx * dx + dy * dy;
22847
22358
  for (let y = y0; y <= y1; y++) {
22848
22359
  for (let x = x0; x <= x1; x++) {
22849
- const px2 = win.x + x + 0.5 - from.x;
22360
+ const px = win.x + x + 0.5 - from.x;
22850
22361
  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;
22362
+ const t = len2 > 0 ? Math.min(1, Math.max(0, (px * dx + py * dy) / len2)) : 0;
22363
+ if ((px - t * dx) ** 2 + (py - t * dy) ** 2 > r * r) continue;
22853
22364
  const i = y * win.width + x;
22854
22365
  area[i] = add2 && !hole[i] ? 1 : 0;
22855
22366
  }
@@ -23414,6 +22925,7 @@ export {
23414
22925
  createImageSubjectSelectionTool,
23415
22926
  createImageTransformTools,
23416
22927
  createImageTypeTools,
22928
+ createLayerEffectTools,
23417
22929
  createMetricTextShaper,
23418
22930
  createOutlineTextShaper,
23419
22931
  createPigment,