@ikijs/editor 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -73,11 +73,12 @@ declare class SetPartTransform extends FieldCommand<number | undefined> {
73
73
  }
74
74
  /**
75
75
  * Capture the warp deformer's grid as one keyform at the driving parameter
76
- * `value`, upserting `offsets` into `warps[0].keyforms`. The 4-tuple-style
76
+ * `value`, upserting `offsets` into the deformer's single grid warp. The 4-tuple-style
77
77
  * mutable `offsets` array is cloned on construction so a later caller mutation
78
78
  * cannot corrupt apply/redo (mirrors {@link SetPartColor}).
79
79
  *
80
- * `apply` validates BEFORE mutating: the deformer must have a grid warp, the
80
+ * `apply` validates BEFORE mutating: the deformer must have exactly one grid
81
+ * warp (several are refused — which driver to write into is ambiguous), the
81
82
  * offsets length must equal `grid.points.length`, and `value` must lie within
82
83
  * the driving parameter's declared `[min,max]` (fail fast, before
83
84
  * `parseIkiModel` would reject it). Prior keyforms are deep-copied once on the
@@ -185,7 +186,8 @@ declare class SetDeformerBindings implements EditCommand {
185
186
  /**
186
187
  * Reparent a deformer (matrix or warp) under a new parent, or promote it to
187
188
  * root (`newParentId === undefined`). Calls {@link validateDeformerReparent}
188
- * FIRST so invalid reparents (cycles, warp parent, unknown id) throw before any
189
+ * FIRST so invalid reparents (cycles, warp-under-warp, a pivot outside the new
190
+ * warp parent's grid, unknown id) throw before any
189
191
  * capture or mutation — a throwing apply leaves the model and undo stack
190
192
  * untouched.
191
193
  *
@@ -1181,8 +1183,10 @@ declare function uvRectFor(placement: AtlasPlacement, page: {
1181
1183
  /**
1182
1184
  * Validate that reparenting `deformerId` under `newParentId` keeps the deformer
1183
1185
  * hierarchy valid. Pass `newParentId === undefined` to move to root (always legal).
1184
- * Checks: existence, self-reference, undeclared parent, kind constraint (warp
1185
- * deformers cannot be parents), and cycle detection via the proposed edge.
1186
+ * Checks: existence, self-reference, undeclared parent, kind constraint (a warp
1187
+ * deformer cannot be the parent of another warp deformer), a matrix deformer's
1188
+ * pivot inside its new warp parent's rest grid, and cycle detection via the
1189
+ * proposed edge.
1186
1190
  */
1187
1191
  declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId: string, newParentId: string | undefined): void;
1188
1192
  /**
package/dist/index.d.ts CHANGED
@@ -73,11 +73,12 @@ declare class SetPartTransform extends FieldCommand<number | undefined> {
73
73
  }
74
74
  /**
75
75
  * Capture the warp deformer's grid as one keyform at the driving parameter
76
- * `value`, upserting `offsets` into `warps[0].keyforms`. The 4-tuple-style
76
+ * `value`, upserting `offsets` into the deformer's single grid warp. The 4-tuple-style
77
77
  * mutable `offsets` array is cloned on construction so a later caller mutation
78
78
  * cannot corrupt apply/redo (mirrors {@link SetPartColor}).
79
79
  *
80
- * `apply` validates BEFORE mutating: the deformer must have a grid warp, the
80
+ * `apply` validates BEFORE mutating: the deformer must have exactly one grid
81
+ * warp (several are refused — which driver to write into is ambiguous), the
81
82
  * offsets length must equal `grid.points.length`, and `value` must lie within
82
83
  * the driving parameter's declared `[min,max]` (fail fast, before
83
84
  * `parseIkiModel` would reject it). Prior keyforms are deep-copied once on the
@@ -185,7 +186,8 @@ declare class SetDeformerBindings implements EditCommand {
185
186
  /**
186
187
  * Reparent a deformer (matrix or warp) under a new parent, or promote it to
187
188
  * root (`newParentId === undefined`). Calls {@link validateDeformerReparent}
188
- * FIRST so invalid reparents (cycles, warp parent, unknown id) throw before any
189
+ * FIRST so invalid reparents (cycles, warp-under-warp, a pivot outside the new
190
+ * warp parent's grid, unknown id) throw before any
189
191
  * capture or mutation — a throwing apply leaves the model and undo stack
190
192
  * untouched.
191
193
  *
@@ -1181,8 +1183,10 @@ declare function uvRectFor(placement: AtlasPlacement, page: {
1181
1183
  /**
1182
1184
  * Validate that reparenting `deformerId` under `newParentId` keeps the deformer
1183
1185
  * hierarchy valid. Pass `newParentId === undefined` to move to root (always legal).
1184
- * Checks: existence, self-reference, undeclared parent, kind constraint (warp
1185
- * deformers cannot be parents), and cycle detection via the proposed edge.
1186
+ * Checks: existence, self-reference, undeclared parent, kind constraint (a warp
1187
+ * deformer cannot be the parent of another warp deformer), a matrix deformer's
1188
+ * pivot inside its new warp parent's rest grid, and cycle detection via the
1189
+ * proposed edge.
1186
1190
  */
1187
1191
  declare function validateDeformerReparent(deformers: IkiDeformer[], deformerId: string, newParentId: string | undefined): void;
1188
1192
  /**
package/dist/index.js CHANGED
@@ -520,11 +520,24 @@ function validateDeformerReparent(deformers2, deformerId, newParentId) {
520
520
  `deformers."${deformerId}".parent "${newParentId}" is not a declared deformer`
521
521
  );
522
522
  }
523
- if (kindOf(parent) === "warp") {
523
+ if (kindOf(parent) === "warp" && kindOf(target) === "warp") {
524
524
  throw new Error(
525
- `deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be parents)`
525
+ `deformers."${deformerId}".parent "${newParentId}" must be a matrix deformer (warp deformers cannot be nested under a warp deformer)`
526
526
  );
527
527
  }
528
+ if (parent.kind === "warp" && target.kind !== "warp") {
529
+ const { pivot } = target;
530
+ const { cols, rows, points } = parent.grid;
531
+ const xMin = points[0];
532
+ const xMax = points[2 * cols];
533
+ const yMax = points[1];
534
+ const yMin = points[rows * (cols + 1) * 2 + 1];
535
+ if (pivot.x < xMin || pivot.x > xMax || pivot.y < yMin || pivot.y > yMax) {
536
+ throw new Error(
537
+ `deformers."${deformerId}".pivot (${pivot.x}, ${pivot.y}) lies outside its warp parent "${newParentId}" rest grid x ${xMin}..${xMax}, y ${yMin}..${yMax}`
538
+ );
539
+ }
540
+ }
528
541
  const parentOf = /* @__PURE__ */ new Map();
529
542
  for (const d of deformers2) {
530
543
  if (d.parent !== void 0) parentOf.set(d.id, d.parent);
@@ -708,6 +721,12 @@ var CaptureGridKeyform = class {
708
721
  prevKeyforms;
709
722
  apply(doc) {
710
723
  const deformer = doc.findWarpDeformer(this.deformerId);
724
+ const count = deformer.warps?.length ?? 0;
725
+ if (count > 1) {
726
+ throw new Error(
727
+ `deformers."${this.deformerId}".warps: ${count} grid warps \u2014 capture targets a deformer with exactly one grid warp (which entry to write into is ambiguous)`
728
+ );
729
+ }
711
730
  const warp = deformer.warps?.[0];
712
731
  if (!warp) {
713
732
  throw new Error(