@pixerate/editor 0.191.0 → 0.193.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 (55) hide show
  1. package/dist/animation-editor/index.cjs +56 -56
  2. package/dist/animation-editor/index.js +2 -2
  3. package/dist/{chunk-ZQGZWFPU.cjs → chunk-3T5VCDIV.cjs} +97 -5
  4. package/dist/{chunk-RQ2EM5TY.js → chunk-5OC22IEO.js} +97 -5
  5. package/dist/{chunk-EGZM52EO.cjs → chunk-BRKVNXDZ.cjs} +354 -125
  6. package/dist/{chunk-XCDGM7TD.cjs → chunk-FR2Q2LVF.cjs} +35 -35
  7. package/dist/{chunk-LPIKXPBM.js → chunk-GHCXLQ47.js} +262 -33
  8. package/dist/{chunk-VRXXAXUT.js → chunk-MLC7HUHO.js} +1 -1
  9. package/dist/{chunk-2UR4OX3B.cjs → chunk-UYXL6ZWQ.cjs} +114 -97
  10. package/dist/{chunk-TXYXF32N.js → chunk-ZIDUPSP4.js} +35 -18
  11. package/dist/image-editor/controller.d.cts +31 -2
  12. package/dist/image-editor/controller.d.ts +31 -2
  13. package/dist/image-editor/index.cjs +1064 -923
  14. package/dist/image-editor/index.js +204 -63
  15. package/dist/image-editor/layers/model.d.cts +7 -2
  16. package/dist/image-editor/layers/model.d.ts +7 -2
  17. package/dist/image-editor/layers/serialize.d.cts +2 -0
  18. package/dist/image-editor/layers/serialize.d.ts +2 -0
  19. package/dist/image-editor/layers/shape-type-ui.d.cts +8 -2
  20. package/dist/image-editor/layers/shape-type-ui.d.ts +8 -2
  21. package/dist/image-editor/layers/text.d.cts +6 -2
  22. package/dist/image-editor/layers/text.d.ts +6 -2
  23. package/dist/image-editor/psd/type.d.cts +2 -1
  24. package/dist/image-editor/psd/type.d.ts +2 -1
  25. package/dist/image-editor/selection/tool-options.d.cts +7 -1
  26. package/dist/image-editor/selection/tool-options.d.ts +7 -1
  27. package/dist/image-editor/tools.d.cts +1 -1
  28. package/dist/image-editor/tools.d.ts +1 -1
  29. package/dist/image-editor/type-tools.d.cts +2 -2
  30. package/dist/image-editor/type-tools.d.ts +2 -2
  31. package/dist/paint-editor/index.cjs +7 -7
  32. package/dist/paint-editor/index.js +2 -2
  33. package/dist/text/layout.d.cts +93 -12
  34. package/dist/text/layout.d.ts +93 -12
  35. package/dist/text/opentype.d.cts +13 -3
  36. package/dist/text/opentype.d.ts +13 -3
  37. package/dist/text/shapers.d.cts +12 -0
  38. package/dist/text/shapers.d.ts +12 -0
  39. package/dist/text/types.d.cts +36 -2
  40. package/dist/text/types.d.ts +36 -2
  41. package/dist/vector/controller.d.cts +8 -0
  42. package/dist/vector/controller.d.ts +8 -0
  43. package/dist/vector/index.cjs +1039 -967
  44. package/dist/vector/index.js +90 -18
  45. package/dist/vector/text.d.cts +5 -3
  46. package/dist/vector/text.d.ts +5 -3
  47. package/dist/vector/textPanel.d.cts +6 -0
  48. package/dist/vector/textPanel.d.ts +6 -0
  49. package/dist/vector/types.d.cts +9 -0
  50. package/dist/vector/types.d.ts +9 -0
  51. package/package.json +1 -1
  52. package/skills/pixerate-image-editor/SKILL.md +4 -2
  53. package/skills/pixerate-image-editor/references/shapes-and-type.md +19 -5
  54. package/skills/pixerate-image-selection-masking/SKILL.md +2 -0
  55. package/skills/pixerate-vector/SKILL.md +9 -3
@@ -16,7 +16,7 @@ import {
16
16
  traceField,
17
17
  traceVectorImage,
18
18
  vectorTraceContours
19
- } from "../chunk-RQ2EM5TY.js";
19
+ } from "../chunk-5OC22IEO.js";
20
20
  import {
21
21
  applyHomography,
22
22
  homographyFromPoints,
@@ -43,7 +43,7 @@ import {
43
43
  reverseMorphContour,
44
44
  subpathToMorphContour,
45
45
  turnMorphContour
46
- } from "../chunk-VRXXAXUT.js";
46
+ } from "../chunk-MLC7HUHO.js";
47
47
  import {
48
48
  DEFAULT_VECTOR_FONT,
49
49
  IDENTITY_MATRIX,
@@ -218,6 +218,7 @@ import {
218
218
  knifePath,
219
219
  layoutVectorText,
220
220
  lineSubpath,
221
+ lineToTextSpace,
221
222
  locateVectorNode,
222
223
  mapBezierPath,
223
224
  mapVectorGradient,
@@ -337,6 +338,8 @@ import {
337
338
  subpathsToBezier,
338
339
  sweepPath,
339
340
  taperWaveFactor,
341
+ textArrowStep,
342
+ textLineMove,
340
343
  tintVectorNode,
341
344
  transformVectorEffects,
342
345
  transformVectorGradient,
@@ -482,6 +485,7 @@ import {
482
485
  vectorTextHasOutlines,
483
486
  vectorTextIndexAt,
484
487
  vectorTextName,
488
+ vectorTextOrientation,
485
489
  vectorTextPaintSource,
486
490
  vectorTextPaths,
487
491
  vectorTextRange,
@@ -512,7 +516,7 @@ import {
512
516
  withVectorStrokes,
513
517
  withVectorTargetPaint,
514
518
  zigzagPaths
515
- } from "../chunk-LPIKXPBM.js";
519
+ } from "../chunk-GHCXLQ47.js";
516
520
  import "../chunk-YXKLVD56.js";
517
521
  import {
518
522
  createProvenance
@@ -13503,6 +13507,8 @@ var VectorEditorController = class _VectorEditorController {
13503
13507
  const own = {};
13504
13508
  for (const key of VECTOR_STYLE_KEYS) if (input[key] !== void 0) own[key] = input[key];
13505
13509
  const text = input.text.replace(/\r\n?/g, "\n");
13510
+ const orientation = vectorTextOrientation(input.orientation);
13511
+ if (orientation && frame.kind === "path") throw new VectorTextError("Text on a path cannot be vertical; leave orientation out, or set point or area text.");
13506
13512
  const node = {
13507
13513
  id: this.newId(),
13508
13514
  type: "text",
@@ -13511,7 +13517,8 @@ var VectorEditorController = class _VectorEditorController {
13511
13517
  text,
13512
13518
  font,
13513
13519
  ...Object.keys(paragraph).length ? { paragraph } : {},
13514
- frame
13520
+ frame,
13521
+ ...orientation ? { orientation } : {}
13515
13522
  };
13516
13523
  return withStyle(node, own);
13517
13524
  }
@@ -13602,12 +13609,19 @@ var VectorEditorController = class _VectorEditorController {
13602
13609
  n2 = { ...n2, paragraph };
13603
13610
  if (!Object.keys(paragraph).length) delete n2.paragraph;
13604
13611
  }
13612
+ if (patch.orientation !== void 0) {
13613
+ const orientation = vectorTextOrientation(patch.orientation);
13614
+ if (orientation && n2.frame.kind === "path") throw new VectorTextError("Text on a path cannot be vertical; set it as point or area text first.");
13615
+ n2 = { ...n2 };
13616
+ if (orientation) n2.orientation = orientation;
13617
+ else delete n2.orientation;
13618
+ }
13605
13619
  next.set(t.id, n2);
13606
13620
  }
13607
13621
  } catch (e) {
13608
13622
  return { ok: false, message: e instanceof Error ? e.message : String(e) };
13609
13623
  }
13610
- this.change(patch.paragraph && !patch.style ? "Paragraph Style" : "Character Style", () => this.setDoc(mapTree(this.doc.nodes, (n2) => next.get(n2.id) ?? n2)), options.merge);
13624
+ this.change(patch.orientation !== void 0 && !patch.style && !patch.paragraph ? "Type Orientation" : patch.paragraph && !patch.style ? "Paragraph Style" : "Character Style", () => this.setDoc(mapTree(this.doc.nodes, (n2) => next.get(n2.id) ?? n2)), options.merge);
13611
13625
  return { ok: true };
13612
13626
  }
13613
13627
  /** Changes paragraph fields (`align`, `autoLeading`, indents, spacing; `null` clears) of text node `id`. One undo step. */
@@ -13637,7 +13651,12 @@ var VectorEditorController = class _VectorEditorController {
13637
13651
  const cur = n2.frame;
13638
13652
  const box = layout.bounds ?? { x: 0, y: 0, width: 0, height: 0 };
13639
13653
  let frame;
13640
- if (kind === "point") {
13654
+ if (n2.orientation === "vertical" && kind === "path") throw new VectorTextError("Text on a path cannot be vertical; call vector.setTextOrientation with horizontal first.");
13655
+ if (kind === "point" && n2.orientation === "vertical" && cur.kind !== "point") {
13656
+ const l = layout.text.lines[0];
13657
+ const at = l ? lineToTextSpace(layout.text, { x: 0, y: l.baseline }) : { x: 0, y: 0 };
13658
+ frame = sanitizeVectorTextFrame({ kind: "point", x: patch.x ?? layout.origin.x + at.x, y: patch.y ?? layout.origin.y + at.y });
13659
+ } else if (kind === "point") {
13641
13660
  const first = layout.lines[0];
13642
13661
  const x = patch.x ?? (cur.kind === "point" ? cur.x : first?.x ?? box.x);
13643
13662
  const y = patch.y ?? (cur.kind === "point" ? cur.y : first?.baseline ?? box.y);
@@ -13657,6 +13676,21 @@ var VectorEditorController = class _VectorEditorController {
13657
13676
  return { ...n2, frame };
13658
13677
  });
13659
13678
  }
13679
+ /**
13680
+ * Horizontal ↔ vertical text (Type › Type Orientation) for point and area text: the text, styles
13681
+ * and frame stay; lines become columns running down, right to left, or back. One undo step.
13682
+ */
13683
+ setTextOrientation(id, orientation) {
13684
+ return this.editTextNode(id, "Type Orientation", (n2) => {
13685
+ const next = vectorTextOrientation(orientation);
13686
+ if (next && n2.frame.kind === "path") throw new VectorTextError("Text on a path cannot be vertical; set it as point or area text first (vector.setTextFrame).");
13687
+ if (next === n2.orientation) return n2;
13688
+ const out = { ...n2 };
13689
+ if (next) out.orientation = next;
13690
+ else delete out.orientation;
13691
+ return out;
13692
+ });
13693
+ }
13660
13694
  /**
13661
13695
  * Turns path `pathId` into text set along it (Type on a Path): a text node in its place, its
13662
13696
  * anchors the text's path, its paint dropped for the text defaults (or `input`'s). Returns the
@@ -13829,7 +13863,11 @@ var VectorEditorController = class _VectorEditorController {
13829
13863
  return false;
13830
13864
  }
13831
13865
  const text = node.text;
13832
- const key = input.key;
13866
+ let key = input.key;
13867
+ if (node.orientation === "vertical" && node.frame.kind !== "path" && (key === "ArrowLeft" || key === "ArrowRight" || key === "ArrowUp" || key === "ArrowDown")) {
13868
+ const step = textArrowStep("vertical", key);
13869
+ key = step === "previous" ? "ArrowLeft" : step === "next" ? "ArrowRight" : step === "line-before" ? "ArrowUp" : "ArrowDown";
13870
+ }
13833
13871
  const move = (to) => {
13834
13872
  const focus = Math.max(0, Math.min(text.length, to));
13835
13873
  this.textEdit = { ...t, focus, anchor: input.shift ? t.anchor : focus };
@@ -13918,11 +13956,7 @@ var VectorEditorController = class _VectorEditorController {
13918
13956
  lineMove(node, index, dir) {
13919
13957
  const layout = layoutVectorText(node);
13920
13958
  if (node.frame.kind === "path") return dir < 0 ? 0 : node.text.length;
13921
- const c = vectorTextCaret(node, index);
13922
- const lines = layout.text.lines;
13923
- const target = lines[c.line + dir];
13924
- if (!target) return dir < 0 ? 0 : node.text.length;
13925
- return vectorTextIndexAt(node, { x: c.top.x, y: layout.origin.y + target.baseline });
13959
+ return textLineMove(layout.text, index, dir, node.text.length);
13926
13960
  }
13927
13961
  /** The topmost node of `type` under `p` (inside groups too, hit where it draws), or null. */
13928
13962
  hitOfType(p, type) {
@@ -15427,6 +15461,7 @@ function createVectorCommands(controller, options = {}) {
15427
15461
  runs,
15428
15462
  paragraph: t.paragraph ?? {},
15429
15463
  frame: t.frame,
15464
+ orientation: t.orientation ?? "horizontal",
15430
15465
  fill: t.fill ?? null,
15431
15466
  stroke: t.stroke ?? null,
15432
15467
  lines: layout.lines.map((l) => ({ start: l.start, end: l.end, text: t.text.slice(l.start, l.end) })),
@@ -15446,7 +15481,13 @@ function createVectorCommands(controller, options = {}) {
15446
15481
  leading: { type: ["number", "null"], minimum: 0, maximum: 1e4, description: "Baseline-to-baseline distance in document units; null for auto (autoLeading \xD7 size)." },
15447
15482
  baselineShift: { type: ["number", "null"], minimum: -5e3, maximum: 5e3, description: "Raises (positive) or lowers the text, document units (0 default)." },
15448
15483
  underline: { type: "boolean", description: "Underline." },
15449
- strikethrough: { type: "boolean", description: "Strike through." }
15484
+ strikethrough: { type: "boolean", description: "Strike through." },
15485
+ upright: { type: "boolean", description: "Vertical text only: Latin and other horizontal-script characters stand upright, one under the other, instead of turned sideways (default false)." }
15486
+ };
15487
+ const ORIENTATION = {
15488
+ type: "string",
15489
+ enum: ["horizontal", "vertical"],
15490
+ description: "horizontal (default): lines left to right, stacked down. vertical: columns top to bottom, stacked right to left; CJK stands upright, Latin turns sideways unless styled upright. Point and area text only."
15450
15491
  };
15451
15492
  const PARAGRAPH_PROPS = {
15452
15493
  align: { type: "string", enum: ["left", "center", "right", "justify"], description: "Alignment (default left). justify stretches area text lines but the last of a paragraph, and spreads path text over the path." },
@@ -15489,7 +15530,7 @@ function createVectorCommands(controller, options = {}) {
15489
15530
  id: `${prefix}addText`,
15490
15531
  label: "Add Text\u2026",
15491
15532
  keywords: ["text", "type", "label", "title", "headline", "caption", "paragraph", "words"],
15492
- description: 'Adds text: point text whose first baseline starts at (x, y), area text wrapped in a box (x, y, width, height), or text along `path` (SVG path data, document units). Paragraphs are separated by "\\n". Paint defaults to black with no stroke; style it with fill / stroke here or vector.setStyle. One undo step. Returns vector.getText\'s summary of the new text (id, lines, bounds, overflow).',
15533
+ description: "Adds text: point text whose first baseline starts at (x, y), area text wrapped in a box (x, y, width, height), or text along `path` (SVG path data, document units). textOrientation vertical sets point or area text in columns running down, right to left: (x, y) is then the top of the first column's centre line, and area text fills its box from the right edge. Paragraphs are separated by \"\\n\". Paint defaults to black with no stroke; style it with fill / stroke here or vector.setStyle. One undo step. Returns vector.getText's summary of the new text (id, lines, bounds, overflow).",
15493
15534
  params: {
15494
15535
  type: "object",
15495
15536
  properties: {
@@ -15502,6 +15543,7 @@ function createVectorCommands(controller, options = {}) {
15502
15543
  ...PATH_TEXT_PROPS,
15503
15544
  font: { type: "object", properties: FONT_PROPS, additionalProperties: false, description: "Character style (default the editor's text defaults: 24 sans-serif)." },
15504
15545
  paragraph: { type: "object", properties: PARAGRAPH_PROPS, additionalProperties: false, description: "Paragraph style." },
15546
+ textOrientation: { ...ORIENTATION, description: `${ORIENTATION.description} Named textOrientation because orientation is the path text option.` },
15505
15547
  name: { type: "string", description: "Layer name (default the text's start)." },
15506
15548
  fill: PAINT,
15507
15549
  stroke: PAINT,
@@ -15524,6 +15566,7 @@ function createVectorCommands(controller, options = {}) {
15524
15566
  ...params.path !== void 0 ? { path: params.path, pathOptions } : {},
15525
15567
  ...params.font ? { font: params.font } : {},
15526
15568
  ...params.paragraph ? { paragraph: params.paragraph } : {},
15569
+ ...params.textOrientation !== void 0 ? { orientation: params.textOrientation } : {},
15527
15570
  ...params.fill !== void 0 ? { fill: checkPaint(params.fill, "fill") } : {},
15528
15571
  ...params.stroke !== void 0 ? { stroke: checkPaint(params.stroke, "stroke") } : {}
15529
15572
  }, parentOf(params.parentId));
@@ -15539,7 +15582,7 @@ function createVectorCommands(controller, options = {}) {
15539
15582
  label: "Get Text",
15540
15583
  readOnly: true,
15541
15584
  keywords: ["text", "type", "read", "font", "runs"],
15542
- description: "Reads a text node: its text, base font, runs (styled ranges as { start, end, style } in UTF-16 code units; style fields override the font, fill a range's colour), paragraph style, frame (point / area / path), fill and stroke, the laid-out lines (start, end, text), document bounds, overflow (text that does not fit its box or path), whether it draws as outlines, the shaper and missing fonts. Use the ranges with vector.setText and vector.setTextStyle.",
15585
+ description: "Reads a text node: its text, base font, runs (styled ranges as { start, end, style } in UTF-16 code units; style fields override the font, fill a range's colour), paragraph style, frame (point / area / path), orientation (horizontal / vertical), fill and stroke, the laid-out lines (start, end, text), document bounds, overflow (text that does not fit its box or path), whether it draws as outlines, the shaper and missing fonts. Use the ranges with vector.setText and vector.setTextStyle.",
15543
15586
  params: { type: "object", properties: { id: { type: "string", description: "Text node id (from vector.list)." } }, required: ["id"], additionalProperties: false },
15544
15587
  run: (_ctx, params) => textSummary(params.id)
15545
15588
  },
@@ -15626,6 +15669,24 @@ function createVectorCommands(controller, options = {}) {
15626
15669
  return textSummary(id);
15627
15670
  }
15628
15671
  },
15672
+ {
15673
+ ...base,
15674
+ id: `${prefix}setTextOrientation`,
15675
+ label: "Type Orientation",
15676
+ keywords: ["vertical text", "vertical type", "horizontal text", "tategaki", "columns", "cjk", "japanese", "chinese", "orientation"],
15677
+ description: "Sets point or area text horizontal (lines left to right) or vertical (columns top to bottom, stacked right to left; CJK upright, Latin turned sideways unless styled upright). The text, styles and frame stay. Text on a path cannot be vertical. One undo step. Returns the text summary with its orientation and lines (columns).",
15678
+ params: {
15679
+ type: "object",
15680
+ properties: { id: { type: "string", description: "Text node id." }, orientation: { ...ORIENTATION, description: "horizontal or vertical." } },
15681
+ required: ["id", "orientation"],
15682
+ additionalProperties: false
15683
+ },
15684
+ undoable: true,
15685
+ run: (_ctx, params) => {
15686
+ check2(controller.setTextOrientation(params.id, params.orientation));
15687
+ return textSummary(params.id);
15688
+ }
15689
+ },
15629
15690
  {
15630
15691
  ...base,
15631
15692
  id: `${prefix}typeOnPath`,
@@ -18274,7 +18335,7 @@ var VECTOR_FONT_WEIGHTS = [
18274
18335
  { value: 700, label: "Bold" },
18275
18336
  { value: 900, label: "Black" }
18276
18337
  ];
18277
- var FIELDS = ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough"];
18338
+ var FIELDS = ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough", "upright"];
18278
18339
  function getVectorTextPanel(state) {
18279
18340
  const nodes = [];
18280
18341
  for (const id of state.selection) {
@@ -18305,7 +18366,7 @@ function getVectorTextPanel(state) {
18305
18366
  styles.push(font2);
18306
18367
  }
18307
18368
  const same = (k) => {
18308
- const values = styles.map((s) => s[k] ?? (k === "italic" || k === "underline" || k === "strikethrough" ? false : k === "leading" ? null : k === "tracking" || k === "baselineShift" ? 0 : null));
18369
+ const values = styles.map((s) => s[k] ?? (k === "italic" || k === "underline" || k === "strikethrough" || k === "upright" ? false : k === "leading" ? null : k === "tracking" || k === "baselineShift" ? 0 : null));
18309
18370
  return values.every((v) => v === values[0]) ? values[0] ?? null : null;
18310
18371
  };
18311
18372
  const font = Object.fromEntries(FIELDS.map((k) => [k, same(k)]));
@@ -18313,7 +18374,11 @@ function getVectorTextPanel(state) {
18313
18374
  const align = alignSource.every((a) => a === alignSource[0]) ? alignSource[0] : null;
18314
18375
  const ids = target === "range" ? [edited.id] : nodes.map((n2) => n2.id);
18315
18376
  const frameNode = target === "range" ? edited : nodes.length === 1 ? nodes[0] : void 0;
18316
- return { target, ids, font, align, frame: frameNode?.frame.kind ?? null, families: vectorTextFamilies(), outlines: vectorTextHasOutlines(), pathId };
18377
+ const edits = target === "range" ? [edited] : nodes;
18378
+ const orientations = edits.map((n2) => n2.orientation ?? "horizontal");
18379
+ const orientation = orientations.length && orientations.every((o) => o === orientations[0]) ? orientations[0] : null;
18380
+ const canOrient = edits.length > 0 && edits.every((n2) => n2.frame.kind !== "path");
18381
+ return { target, ids, font, align, frame: frameNode?.frame.kind ?? null, orientation, canOrient, families: vectorTextFamilies(), outlines: vectorTextHasOutlines(), pathId };
18317
18382
  }
18318
18383
  function applyVectorTextStyle(controller, patch, options = {}) {
18319
18384
  const state = controller.getState();
@@ -18339,6 +18404,11 @@ function applyVectorParagraphStyle(controller, patch, options = {}) {
18339
18404
  }
18340
18405
  controller.styleTexts({ paragraph: patch }, { ids: panel.ids, ...options });
18341
18406
  }
18407
+ function applyVectorTextOrientation(controller, orientation) {
18408
+ const panel = getVectorTextPanel(controller.getState());
18409
+ if (!panel || !panel.canOrient) return;
18410
+ controller.styleTexts({ orientation }, { ids: panel.ids });
18411
+ }
18342
18412
 
18343
18413
  // src/vector/symbolsPanel.ts
18344
18414
  var fmt3 = (n2) => Math.round(n2 * 100) / 100;
@@ -18627,6 +18697,7 @@ export {
18627
18697
  applyVectorGradientSpread,
18628
18698
  applyHomography as applyVectorHomography,
18629
18699
  applyVectorParagraphStyle,
18700
+ applyVectorTextOrientation,
18630
18701
  applyVectorTextStyle,
18631
18702
  arrowheadInset,
18632
18703
  arrowheadPath,
@@ -19156,6 +19227,7 @@ export {
19156
19227
  vectorTextHasOutlines,
19157
19228
  vectorTextIndexAt,
19158
19229
  vectorTextName,
19230
+ vectorTextOrientation,
19159
19231
  vectorTextPaintSource,
19160
19232
  vectorTextPaths,
19161
19233
  vectorTextRange,
@@ -29,7 +29,7 @@ export declare function vectorTextHasOutlines(): boolean;
29
29
  export declare function vectorTextFamilies(): string[];
30
30
  export declare const DEFAULT_VECTOR_FONT: Readonly<VectorCharacterStyle>;
31
31
  /** Character style fields, in the order agents see them. */
32
- export declare const VECTOR_CHARACTER_STYLE_KEYS: readonly ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough"];
32
+ export declare const VECTOR_CHARACTER_STYLE_KEYS: readonly ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough", "upright"];
33
33
  /** Paragraph style fields. */
34
34
  export declare const VECTOR_PARAGRAPH_STYLE_KEYS: readonly ["align", "autoLeading", "firstLineIndent", "startIndent", "endIndent", "spaceBefore", "spaceAfter"];
35
35
  export declare class VectorTextError extends Error {
@@ -115,7 +115,7 @@ export interface VectorTextLayout {
115
115
  shaper: string;
116
116
  glyphs: VectorTextGlyph[];
117
117
  fragments: VectorTextFragment[];
118
- /** Lines: their text range and baseline (node space for point and area text). */
118
+ /** Lines: their text range and baseline (node space for point and area text; for vertical text `baseline` is a column's centre x and `x` its top y). */
119
119
  lines: {
120
120
  start: number;
121
121
  end: number;
@@ -183,8 +183,10 @@ export declare function patchVectorParagraphStyle(base: VectorParagraphStyle, pa
183
183
  export declare function sanitizeVectorTextFrame(value: unknown, path?: string): VectorTextFrame;
184
184
  /** Normalised runs: fitted to the text, empty overrides dropped, `null` when there is one plain style. */
185
185
  export declare function normalizeVectorTextRuns(text: string, runs: readonly VectorTextRun[] | null | undefined): VectorTextRun[] | null;
186
+ /** An orientation from loose input: `horizontal` (returned as undefined, the default) or `vertical`. */
187
+ export declare function vectorTextOrientation(value: unknown, path?: string): 'vertical' | undefined;
186
188
  /** A text node read from untrusted data (JSON, SVG data attributes, agents): fields validated and normalised. */
187
- export declare function sanitizeVectorTextFields(value: Record<string, unknown>): Pick<VectorTextNode, 'text' | 'font' | 'runs' | 'paragraph' | 'frame'>;
189
+ export declare function sanitizeVectorTextFields(value: Record<string, unknown>): Pick<VectorTextNode, 'text' | 'font' | 'runs' | 'paragraph' | 'frame' | 'orientation'>;
188
190
  /** A range of the text from loose input: [start, end) in UTF-16 code units (default the whole text). */
189
191
  export declare function vectorTextRange(text: string, start: unknown, end: unknown): [number, number];
190
192
  /** The node with [start, end) of its text replaced by `insert` (styled like the character before it). */
@@ -29,7 +29,7 @@ export declare function vectorTextHasOutlines(): boolean;
29
29
  export declare function vectorTextFamilies(): string[];
30
30
  export declare const DEFAULT_VECTOR_FONT: Readonly<VectorCharacterStyle>;
31
31
  /** Character style fields, in the order agents see them. */
32
- export declare const VECTOR_CHARACTER_STYLE_KEYS: readonly ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough"];
32
+ export declare const VECTOR_CHARACTER_STYLE_KEYS: readonly ["fontFamily", "fontWeight", "italic", "fontSize", "tracking", "leading", "baselineShift", "underline", "strikethrough", "upright"];
33
33
  /** Paragraph style fields. */
34
34
  export declare const VECTOR_PARAGRAPH_STYLE_KEYS: readonly ["align", "autoLeading", "firstLineIndent", "startIndent", "endIndent", "spaceBefore", "spaceAfter"];
35
35
  export declare class VectorTextError extends Error {
@@ -115,7 +115,7 @@ export interface VectorTextLayout {
115
115
  shaper: string;
116
116
  glyphs: VectorTextGlyph[];
117
117
  fragments: VectorTextFragment[];
118
- /** Lines: their text range and baseline (node space for point and area text). */
118
+ /** Lines: their text range and baseline (node space for point and area text; for vertical text `baseline` is a column's centre x and `x` its top y). */
119
119
  lines: {
120
120
  start: number;
121
121
  end: number;
@@ -183,8 +183,10 @@ export declare function patchVectorParagraphStyle(base: VectorParagraphStyle, pa
183
183
  export declare function sanitizeVectorTextFrame(value: unknown, path?: string): VectorTextFrame;
184
184
  /** Normalised runs: fitted to the text, empty overrides dropped, `null` when there is one plain style. */
185
185
  export declare function normalizeVectorTextRuns(text: string, runs: readonly VectorTextRun[] | null | undefined): VectorTextRun[] | null;
186
+ /** An orientation from loose input: `horizontal` (returned as undefined, the default) or `vertical`. */
187
+ export declare function vectorTextOrientation(value: unknown, path?: string): 'vertical' | undefined;
186
188
  /** A text node read from untrusted data (JSON, SVG data attributes, agents): fields validated and normalised. */
187
- export declare function sanitizeVectorTextFields(value: Record<string, unknown>): Pick<VectorTextNode, 'text' | 'font' | 'runs' | 'paragraph' | 'frame'>;
189
+ export declare function sanitizeVectorTextFields(value: Record<string, unknown>): Pick<VectorTextNode, 'text' | 'font' | 'runs' | 'paragraph' | 'frame' | 'orientation'>;
188
190
  /** A range of the text from loose input: [start, end) in UTF-16 code units (default the whole text). */
189
191
  export declare function vectorTextRange(text: string, start: unknown, end: unknown): [number, number];
190
192
  /** The node with [start, end) of its text replaced by `insert` (styled like the character before it). */
@@ -17,6 +17,10 @@ export interface VectorTextPanelData {
17
17
  align: VectorTextAlign | null;
18
18
  /** The frame kind of a single text node. */
19
19
  frame: 'point' | 'area' | 'path' | null;
20
+ /** The orientation of the text edited (`null` when it mixes, or for new text). */
21
+ orientation: 'horizontal' | 'vertical' | null;
22
+ /** Whether the text edited can turn vertical (none of it is on a path). */
23
+ canOrient: boolean;
20
24
  /** Families the shaper can draw (always the generic ones too). */
21
25
  families: string[];
22
26
  /** Whether the shaper gives outlines (Create Outlines works). */
@@ -52,3 +56,5 @@ export declare function applyVectorParagraphStyle(controller: VectorEditorContro
52
56
  } & Record<string, unknown>, options?: {
53
57
  merge?: string;
54
58
  }): void;
59
+ /** Sets the text being edited or selected horizontal or vertical (one undo step); nothing for new-text defaults or path text. */
60
+ export declare function applyVectorTextOrientation(controller: VectorEditorController, orientation: 'horizontal' | 'vertical'): void;
@@ -17,6 +17,10 @@ export interface VectorTextPanelData {
17
17
  align: VectorTextAlign | null;
18
18
  /** The frame kind of a single text node. */
19
19
  frame: 'point' | 'area' | 'path' | null;
20
+ /** The orientation of the text edited (`null` when it mixes, or for new text). */
21
+ orientation: 'horizontal' | 'vertical' | null;
22
+ /** Whether the text edited can turn vertical (none of it is on a path). */
23
+ canOrient: boolean;
20
24
  /** Families the shaper can draw (always the generic ones too). */
21
25
  families: string[];
22
26
  /** Whether the shaper gives outlines (Create Outlines works). */
@@ -52,3 +56,5 @@ export declare function applyVectorParagraphStyle(controller: VectorEditorContro
52
56
  } & Record<string, unknown>, options?: {
53
57
  merge?: string;
54
58
  }): void;
59
+ /** Sets the text being edited or selected horizontal or vertical (one undo step); nothing for new-text defaults or path text. */
60
+ export declare function applyVectorTextOrientation(controller: VectorEditorController, orientation: 'horizontal' | 'vertical'): void;
@@ -620,6 +620,8 @@ export interface VectorCharacterStyle {
620
620
  baselineShift?: number;
621
621
  underline?: boolean;
622
622
  strikethrough?: boolean;
623
+ /** Vertical text only: Latin and other horizontal scripts stand upright instead of turned sideways (default false). */
624
+ upright?: boolean;
623
625
  }
624
626
  /** Character style fields a run can set over the node's own style, plus its own fill. */
625
627
  export type VectorTextRunStyle = Partial<VectorCharacterStyle> & {
@@ -695,6 +697,13 @@ export interface VectorTextNode extends VectorNodeBase, VectorStyle {
695
697
  runs?: VectorTextRun[] | null;
696
698
  paragraph?: VectorParagraphStyle | null;
697
699
  frame: VectorTextFrame;
700
+ /**
701
+ * Missing = horizontal. `vertical` (point and area text): columns running down, stacked right to
702
+ * left; point text starts at the top of the first column's centre line, area text fills its box
703
+ * from the right edge. CJK characters stand upright, others turn sideways (unless `upright`).
704
+ * Text on a path ignores it.
705
+ */
706
+ orientation?: 'vertical';
698
707
  }
699
708
  /**
700
709
  * Per-instance changes to a symbol's art: every fill and / or stroke of the art painted with one
@@ -620,6 +620,8 @@ export interface VectorCharacterStyle {
620
620
  baselineShift?: number;
621
621
  underline?: boolean;
622
622
  strikethrough?: boolean;
623
+ /** Vertical text only: Latin and other horizontal scripts stand upright instead of turned sideways (default false). */
624
+ upright?: boolean;
623
625
  }
624
626
  /** Character style fields a run can set over the node's own style, plus its own fill. */
625
627
  export type VectorTextRunStyle = Partial<VectorCharacterStyle> & {
@@ -695,6 +697,13 @@ export interface VectorTextNode extends VectorNodeBase, VectorStyle {
695
697
  runs?: VectorTextRun[] | null;
696
698
  paragraph?: VectorParagraphStyle | null;
697
699
  frame: VectorTextFrame;
700
+ /**
701
+ * Missing = horizontal. `vertical` (point and area text): columns running down, stacked right to
702
+ * left; point text starts at the top of the first column's centre line, area text fills its box
703
+ * from the right edge. CJK characters stand upright, others turn sideways (unless `upright`).
704
+ * Text on a path ignores it.
705
+ */
706
+ orientation?: 'vertical';
698
707
  }
699
708
  /**
700
709
  * Per-instance changes to a symbol's art: every fill and / or stroke of the art painted with one
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pixerate/editor",
3
- "version": "0.191.0",
3
+ "version": "0.193.0",
4
4
  "description": "UI-agnostic rich text and media editing core library",
5
5
  "author": "Pixerate",
6
6
  "license": "MIT",
@@ -301,12 +301,14 @@ in the source frame at the document's bit depth, colour mode and profile. Read
301
301
  | `remove_layer_mask` | Delete a mask without applying it; disable it instead to keep it. |
302
302
  | `layer_via_copy` | Copy the selected pixels of a pixel layer (default the active one) to a new layer above it; `cut: true` removes them from the source. Needs a selection. Returns the new layer. |
303
303
  | `rasterize_layer` | Turn a shape layer into a pixel layer showing the same pixels (same id, mask, effects, opacity, blend; the paths are gone), an annotation layer into pixels (browser only), a smart object into a pixel layer (as `rasterize_smart_object`), or bake a pixel layer's develop / blur filters into its pixels. Do it before painting over a shape or annotation, or when the user wants the filters fixed. Destructive. |
304
- | `add_text_layer` | Add live type above the active layer and make it active: `text`, `x`, `y`, optional `box` (paragraph text), `style`, `paragraph`, `rotation`, `name`, `opacity`, `blend`, placement. Returns the `layer` and `text` (with `lines` and `missingFonts`). One undo step. |
304
+ | `add_text_layer` | Add live type above the active layer and make it active: `text`, `x`, `y`, optional `box` (paragraph text), `orientation` (`vertical`: columns down from `x`, `y`, right to left, for Japanese / Chinese / Korean), `style`, `paragraph`, `rotation`, `name`, `opacity`, `blend`, placement. Returns the `layer` and `text` (with `orientation`, `lines` and `missingFonts`). One undo step. |
305
305
  | `set_text` | Replace text `start`..`end` (default all) with `text`; start = end inserts. New text takes the style at `start`. Returns the text layer. |
306
- | `set_text_style` | Set character style fields over `start`..`end` (default all): `fontFamily`, `fontWeight`, `italic`, `fontSize`, `color`, `opacity`, `tracking`, `leading`, `baselineShift`, `underline`, `strikethrough` (`null` resets optional ones). Returns the runs. |
306
+ | `set_text_style` | Set character style fields over `start`..`end` (default all): `fontFamily`, `fontWeight`, `italic`, `fontSize`, `color`, `opacity`, `tracking`, `leading`, `baselineShift`, `underline`, `strikethrough`, `upright` (vertical text: Latin upright instead of turned) (`null` resets optional ones). Returns the runs. |
307
307
  | `set_paragraph_style` | Set `align`, `autoLeading`, indents, `spaceBefore` / `spaceAfter` on every paragraph `start`..`end` touches (default all). Returns the text layer. |
308
308
  | `set_text_frame` | `kind: point` (one line per paragraph) or `kind: box` with `width` and `height` (wrapping paragraph text), or resize a box; the first line stays put. Returns the text layer and its lines. |
309
+ | `set_text_orientation` | Type › Orientation: `horizontal` or `vertical` (columns top to bottom, right to left; CJK upright, Latin turned sideways unless `upright`). Text, styles, frame and origin stay. Returns the text layer with its new lines (columns). One undo step. |
309
310
  | `convert_text_to_shape` | Type › Convert to Shape: glyph outlines become a shape layer with the same id (text no longer editable; fill from the first run's colour; `warnings` lists losses). Needs an outline font shaper. Destructive. |
311
+ | `select_text_shape` | Horizontal / Vertical Type Mask: select the shape of `text` at `x`, `y` (style, box, rotation as `add_text_layer`; `orientation` `vertical` lays it out as vertical type: columns down from `x`, `y`, right to left, CJK upright, Latin turned), by `mode`, with `feather`. No layer is added. Returns the selection. |
310
312
  | `add_shape_layer` | Add a vector shape layer above the active layer (or placed with `aboveId` / `belowId` / `parentId` / `index`) and make it active: `shape` (live rect, ellipse, polygon, star or line, document px), `subpaths` (SVG path data or anchors) or several `components` with path ops; `fill` (colour, gradient or pattern, default the foreground colour; `null` none), `stroke` (`width`, `paint`, `align`, `cap`, `join`, `miterLimit`, `dashes` in widths), `fillRule`, `name`, `opacity`, `blend`. Returns the `layer` and the `shape`. One undo step. |
311
313
  | `update_shape` | Restyle a shape: `fill` (replace, `null` removes), `stroke` (only the settings given change; `null` removes; a new stroke needs `width` and `paint`), `fillRule`. Geometry is unchanged. Returns the shape. |
312
314
  | `set_shape_component` | Change component `componentIndex` (from `get_shape_layer`): `shape` fields (without `kind`, or with the same kind, unset fields keep their values), new `subpaths` (ends the live shape), or `op`. Returns the shape. |
@@ -20,7 +20,7 @@ Detail for the `pixerate-image-editor` skill: how to draw and edit vector shapes
20
20
  `x2` / `y2`, …; the rest stay), replaces a component's `subpaths` (ending its live shape) or
21
21
  changes its `op`. `update_shape` restyles the fill, the stroke (only the settings given) or the
22
22
  fill rule. Read `get_shape_layer` first for the component indices.
23
- 4. **Place it**: `offset_layer`, `transform_layer`, `flip_layer`, `rotate_layer_90` and `warp_layer`
23
+ 5. **Place it**: `offset_layer`, `transform_layer`, `flip_layer`, `rotate_layer_90` and `warp_layer`
24
24
  map the paths, never resample pixels; live shapes stay live under moves, scales, rotations and
25
25
  skews (perspective and warps turn them into plain paths). Stroke widths do not scale.
26
26
  5. **Style it like any layer**: masks, clipping, blend modes, opacity, fill opacity and layer
@@ -36,25 +36,39 @@ Detail for the `pixerate-image-editor` skill: how to draw and edit vector shapes
36
36
  `italic`, `fontSize` in px, `color`, `tracking` in 1/1000 em, `leading` in px, `baselineShift`,
37
37
  `underline`, `strikethrough`) and a `paragraph` style (`align`, `autoLeading`, indents,
38
38
  `spaceBefore` / `spaceAfter`). Call `list_fonts` first when the font matters: a missing family
39
- draws with a fallback and comes back in `missingFonts`.
39
+ draws with a fallback and comes back in `missingFonts`. For Japanese, Chinese or Korean set in
40
+ columns pass `orientation: "vertical"` (or switch later with `set_text_orientation`): columns
41
+ run down from (`x`, `y`), the top of the first column's centre line, and stack right to left;
42
+ a vertical `box` fills from its right edge and wraps at its height.
40
43
  2. **Edit by range**: ranges are `start` / `end` in UTF-16 code units, `end` exclusive, as
41
44
  `get_text_layer` reports runs and lines. `set_text` replaces a range (start = end inserts; new
42
45
  text takes the style at `start`), `set_text_style` styles a range (only the fields given),
43
46
  `set_paragraph_style` styles the paragraphs a range touches. Re-read the runs after an edit
44
47
  that changes the length before using old ranges.
45
48
  3. **Shape the block**: `set_text_frame` switches between point text and a wrapping box (or
46
- resizes the box) with the first line kept in place.
49
+ resizes the box) with the first line kept in place (vertically, the first column's top-right).
50
+ 4. **Vertical text**: ideographs, kana and Hangul stand upright; Latin, digits and spaces turn
51
+ 90° clockwise, which suits words inside Japanese text. For short Latin or acronyms that should
52
+ read down letter by letter, set `upright: true` on that range with `set_text_style`. Brackets,
53
+ dashes and 、。 use the font's vertical forms when the shaper reads them (an outline shaper over
54
+ an OpenType font with `vert`); the browser canvas turns brackets and moves 、。 to the upper
55
+ right instead. In `get_text_layer`, `lines` are columns: `baseline` is a column's centre in
56
+ line space, not a y. Use a font with CJK glyphs (`list_fonts`): a Latin-only family draws CJK
57
+ with a fallback.
47
58
  4. **Place it**: `offset_layer`, `transform_layer`, `flip_layer` and `rotate_layer_90` change the
48
59
  text's matrix and draw it again (scale, rotate, skew, flips). Distort, perspective and warp are
49
60
  refused: rasterize first. Masks, clipping, blend modes and effects work as on any layer.
50
- 5. **Outlines and pixels**: `convert_text_to_shape` makes glyph outlines a shape layer (needs an
61
+ 6. **Outlines and pixels**: `convert_text_to_shape` makes glyph outlines a shape layer (needs an
51
62
  outline font shaper; the browser canvas cannot); `rasterize_layer` makes it pixels.
63
+ For a selection in the shape of text (photo-filled letters, text cut out of the image) use
64
+ `select_text_shape`, the Type Mask: it lays the text out the same way but adds no layer.
52
65
 
53
66
  ## Photoshop files
54
67
 
55
68
  `import_psd` brings Photoshop shape layers in as live shapes (paths with their path operations, fill,
56
69
  stroke, and live rectangles, rounded rectangles, ellipses and lines) and type layers as live text
57
- that shows Photoshop's pixels until it is edited. `get_text_layer` reports `rendering: "stored"`
70
+ that shows Photoshop's pixels until it is edited; vertical type comes in vertical (with its
71
+ upright-Latin runs) and goes back out as vertical type. `get_text_layer` reports `rendering: "stored"`
58
72
  and `missingFonts` for those: if a font is missing, edits draw with a fallback, so tell the user
59
73
  before editing such text, or pick an available font with `set_text_style`. `export_psd` writes both
60
74
  kinds back as Photoshop layers; unchanged ones are written byte for byte as they were read.
@@ -106,6 +106,7 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
106
106
  | A cutout, shape or text already on its own layer | `select_layer_transparency` (exact, soft where the layer is) |
107
107
  | A dead pixel row or column | `select_line`, then fill or heal it |
108
108
  | Smooth curves you can describe (a logo, a road, a lens) | `path_to_selection` with Bézier `subpaths` or SVG path data |
109
+ | Letters (photo-filled text, text cut out of the image) | `select_text_shape` (check fonts with `list_fonts`), then `add_layer_mask` or `layer_via_copy` |
109
110
 
110
111
  ## Recipes
111
112
 
@@ -203,6 +204,7 @@ This skill is the method. `pixerate-image-editor` has the full tool reference.
203
204
  - `add_vector_mask`, `set_vector_mask_path`, `set_vector_mask_properties`, `get_vector_mask`: sharp, editable path masks
204
205
  - `rasterize_vector_mask`, `remove_vector_mask`: turn a vector mask into pixels, or drop it
205
206
  - `selection_to_path`, `path_to_selection`: a selection's outline as Bézier paths, and a path back into a selection
207
+ - `select_text_shape`: the Type Mask, a selection in the shape of text
206
208
  - `modify_selection`: expand, contract, feather, border, smooth
207
209
  - `refine_selection`: snap the edge to the image
208
210
  - `transform_selection`: move or scale the outline only
@@ -106,6 +106,11 @@ Parameter details (gradient fields, effect parameters, width profiles, envelopes
106
106
  than splitting text into separate nodes, so it still edits as one paragraph. Create Outlines
107
107
  only for final artwork or logos that must not depend on fonts; keep a copy as text if it may
108
108
  change.
109
+ For Japanese, Chinese or Korean set in columns (signage, book spines, posters), use vertical
110
+ text (`textOrientation: "vertical"` or `vector.setTextOrientation`): CJK stands upright, Latin
111
+ turns sideways; set a short Latin range `upright: true` to stack it letter by letter. In an
112
+ area, columns that do not fit past the left edge are `overflow`. Vertical text cannot follow a
113
+ path.
109
114
 
110
115
  - **Clean paths.** Use the fewest anchors that describe the shape: anchors at extrema (top,
111
116
  bottom, left, right of a curve) and at true corners, handles horizontal or vertical at extrema,
@@ -260,12 +265,13 @@ arrays, to build or replace a stack in one call.
260
265
  | Command | Use it to |
261
266
  | --- | --- |
262
267
  | `vector.listFonts` | See which families the text shaper can draw and whether it gives glyph outlines (`outlines`); read it before choosing fonts or calling `vector.createOutlines`. Returns `{ shaper, outlines, families }`. |
263
- | `vector.addText` | Add point text (`x`, `y`: the first baseline's start), area text (`x`, `y`, `width`, `height`: wrapped in the box) or text along `path` (SVG path data, with `start`, `end`, `flip`, `orientation`, `baseline`). `font`, `paragraph`, `name`, `fill`, `stroke`, `strokeWidth` optional; black, no stroke by default. Returns the text summary (`id`, lines, bounds, overflow). |
264
- | `vector.getText` | Read a text node: text, base font, runs as `{ start, end, style }`, paragraph, frame, fill, stroke, laid-out lines, document bounds, `overflow`, `outlines`, shaper and missing fonts. Call before editing ranges. |
268
+ | `vector.addText` | Add point text (`x`, `y`: the first baseline's start), area text (`x`, `y`, `width`, `height`: wrapped in the box) or text along `path` (SVG path data, with `start`, `end`, `flip`, `orientation`, `baseline`). `textOrientation: "vertical"` sets point or area text in columns down and right to left (`x`, `y` the top of the first column's centre; an area fills from its right edge). `font`, `paragraph`, `name`, `fill`, `stroke`, `strokeWidth` optional; black, no stroke by default. Returns the text summary (`id`, `orientation`, lines, bounds, overflow). |
269
+ | `vector.getText` | Read a text node: text, base font, runs as `{ start, end, style }`, paragraph, frame, `orientation`, fill, stroke, laid-out lines, document bounds, `overflow`, `outlines`, shaper and missing fonts. Call before editing ranges. |
265
270
  | `vector.setText` | Replace `[start, end)` of the text with `text` (default the whole text; `start` = `end` inserts, `""` deletes). Inserted characters take the style before them. Returns the summary. |
266
- | `vector.setTextStyle` | Set character fields (`fontFamily`, `fontWeight`, `italic`, `fontSize`, `tracking`, `leading`, `baselineShift`, `underline`, `strikethrough`; null clears) and `fill` over `[start, end)`; the whole text (default) changes the base font and the node's fill. Returns the summary with runs. |
271
+ | `vector.setTextStyle` | Set character fields (`fontFamily`, `fontWeight`, `italic`, `fontSize`, `tracking`, `leading`, `baselineShift`, `underline`, `strikethrough`, `upright` for Latin standing upright in vertical text; null clears) and `fill` over `[start, end)`; the whole text (default) changes the base font and the node's fill. Returns the summary with runs. |
267
272
  | `vector.setParagraphStyle` | Set `align` (left, center, right, justify), `autoLeading`, indents and spacing for the node's paragraphs. Returns the summary. |
268
273
  | `vector.setTextFrame` | Switch between point, area and path text (`kind`), resize an area (`width`, `height`), move the origin (`x`, `y`) or change path options. Returns the summary. |
274
+ | `vector.setTextOrientation` | Set point or area text `horizontal` or `vertical` (columns top to bottom, right to left; CJK upright, Latin turned sideways unless `upright`). Text on a path cannot be vertical. Returns the summary. |
269
275
  | `vector.typeOnPath` | Turn path node `pathId` into text along it (it takes the path's place and drops its paint) with `text`, `font`, `paragraph` (`align` places it along the path) and path options. Returns the summary with the new id. |
270
276
  | `vector.createOutlines` | Turn text (`ids`, or text inside groups; default the selection) into paths of its glyph outlines, keeping paint, effects, filters, placement and id. Needs `outlines: true` from `vector.listFonts`. Returns `{ ids }`. |
271
277