@flighthq/node 0.3.1-next.861.5a56d7a → 0.3.1-next.948.85d9f30

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 (42) hide show
  1. package/dist/boundsRectangle.d.ts +3 -3
  2. package/dist/boundsRectangle.d.ts.map +1 -1
  3. package/dist/boundsRectangle.js +63 -11
  4. package/dist/boundsRectangle.js.map +1 -1
  5. package/dist/hasAppearance.d.ts +2 -1
  6. package/dist/hasAppearance.d.ts.map +1 -1
  7. package/dist/hasAppearance.js +10 -0
  8. package/dist/hasAppearance.js.map +1 -1
  9. package/dist/hasBoundsRectangle.d.ts.map +1 -1
  10. package/dist/hasBoundsRectangle.js +4 -0
  11. package/dist/hasBoundsRectangle.js.map +1 -1
  12. package/dist/hasTransform3d.d.ts.map +1 -1
  13. package/dist/hasTransform3d.js +11 -4
  14. package/dist/hasTransform3d.js.map +1 -1
  15. package/dist/hierarchy.d.ts +3 -3
  16. package/dist/hierarchy.d.ts.map +1 -1
  17. package/dist/hierarchy.js +20 -20
  18. package/dist/hierarchy.js.map +1 -1
  19. package/dist/nodeOrderList.d.ts.map +1 -1
  20. package/dist/nodeOrderList.js +9 -2
  21. package/dist/nodeOrderList.js.map +1 -1
  22. package/dist/nodeTransform2d.d.ts.map +1 -1
  23. package/dist/nodeTransform2d.js +1 -1
  24. package/dist/nodeTransform2d.js.map +1 -1
  25. package/dist/revision.d.ts +2 -1
  26. package/dist/revision.d.ts.map +1 -1
  27. package/dist/revision.js +9 -4
  28. package/dist/revision.js.map +1 -1
  29. package/dist/stageFit.d.ts.map +1 -1
  30. package/dist/stageFit.js +8 -2
  31. package/dist/stageFit.js.map +1 -1
  32. package/package.json +8 -7
  33. package/src/boundsRectangle.test.ts +228 -5
  34. package/src/hasAppearance.test.ts +33 -3
  35. package/src/hasTransform2d.test.ts +6 -0
  36. package/src/hasTransform3d.test.ts +40 -8
  37. package/src/hierarchy.test.ts +67 -3
  38. package/src/nodeOrderList.test.ts +75 -18
  39. package/src/nodeTransform2d.test.ts +23 -0
  40. package/src/revision.test.ts +26 -0
  41. package/src/stageFit.test.ts +56 -1
  42. package/src/traversal.test.ts +6 -0
@@ -44,7 +44,8 @@ export declare function invalidateNodeParentReference<Traits extends object>(tar
44
44
  */
45
45
  export declare function invalidateNodeRender<Traits extends object>(target: Node<Traits>): void;
46
46
  /**
47
- * Target object's child bounds have changed.
47
+ * Target object's child bounds have changed. Invalidates the target and every ancestor whose
48
+ * aggregate world bounds include it.
48
49
  */
49
50
  export declare function invalidateNodeWorldBounds<Traits extends object>(target: Node<Traits>): void;
50
51
  //# sourceMappingURL=revision.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"revision.d.ts","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAUlE,wBAAgB,iCAAiC,CAAC,MAAM,SAAS,MAAM,EACrE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,aAAa,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAC5C,IAAI,CAON;AAED,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAEvG;AAED,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAErG;AAED,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAExG;AAED,wBAAgB,2BAA2B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAEzG;AAED,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE3G;AAED,wBAAgB,8BAA8B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE5G;AAED,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE3G;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAGnF;AAED,wBAAgB,cAAc,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAOhF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG1F;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG3F;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG5F;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG9F;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAI/F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAGtF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAI3F"}
1
+ {"version":3,"file":"revision.d.ts","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAUlE,wBAAgB,iCAAiC,CAAC,MAAM,SAAS,MAAM,EACrE,OAAO,EAAE,WAAW,CAAC,MAAM,CAAC,EAC5B,aAAa,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAC5C,IAAI,CAON;AAED,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAEvG;AAED,wBAAgB,uBAAuB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAErG;AAED,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAExG;AAED,wBAAgB,2BAA2B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAEzG;AAED,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE3G;AAED,wBAAgB,8BAA8B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE5G;AAED,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAE3G;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAGnF;AAED,wBAAgB,cAAc,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAOhF;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG1F;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG3F;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG5F;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAG9F;AAED;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAI/F;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAGtF;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,SAAS,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAQ3F"}
package/dist/revision.js CHANGED
@@ -101,12 +101,17 @@ export function invalidateNodeRender(target) {
101
101
  invalidateNodeLocalTransform(target);
102
102
  }
103
103
  /**
104
- * Target object's child bounds have changed.
104
+ * Target object's child bounds have changed. Invalidates the target and every ancestor whose
105
+ * aggregate world bounds include it.
105
106
  */
106
107
  export function invalidateNodeWorldBounds(target) {
107
- const runtime = getNodeRuntime(target);
108
- runtime.worldBoundsUsingWorldTransformId = -1;
109
- runtime.worldBoundsUsingLocalBoundsId = -1;
108
+ let current = target;
109
+ while (current !== null) {
110
+ const runtime = getNodeRuntime(current);
111
+ runtime.worldBoundsUsingWorldTransformId = -1;
112
+ runtime.worldBoundsUsingLocalBoundsId = -1;
113
+ current = runtime.parent;
114
+ }
110
115
  }
111
116
  // Monotonic source of world-transform revisions, shared across all nodes so a parent recompute always
112
117
  // yields an id its children have not seen. Runtime-only (never serialized); wraps at 32 bits.
@@ -1 +1 @@
1
- {"version":3,"file":"revision.js","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"revision.js","sourceRoot":"","sources":["../src/revision.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"stageFit.d.ts","sourceRoot":"","sources":["../src/stageFit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,UAAU,EACV,UAAU,EAEV,iBAAiB,EACjB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAQlC,wBAAgB,uBAAuB,CAAC,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAInH;AAGD,wBAAgB,uBAAuB,CAAC,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAIrH;AAGD,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAGD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAMD,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,GAAG,UAAU,EAC3E,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,IAAI,CA6CN"}
1
+ {"version":3,"file":"stageFit.d.ts","sourceRoot":"","sources":["../src/stageFit.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,UAAU,EACV,UAAU,EAEV,iBAAiB,EACjB,aAAa,EACd,MAAM,0BAA0B,CAAC;AAQlC,wBAAgB,uBAAuB,CAAC,kBAAkB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAInH;AAGD,wBAAgB,uBAAuB,CAAC,mBAAmB,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAIrH;AAGD,wBAAgB,0BAA0B,CACxC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAGD,wBAAgB,sBAAsB,CACpC,YAAY,EAAE,MAAM,EACpB,aAAa,EAAE,MAAM,EACrB,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,MAAM,CAER;AAMD,wBAAgB,0BAA0B,CAAC,MAAM,SAAS,MAAM,GAAG,UAAU,EAC3E,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,QAAQ,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC,EAC5C,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,IAAI,CAmDN"}
package/dist/stageFit.js CHANGED
@@ -32,14 +32,20 @@ export function computeScene2DFitScale(contentWidth, contentHeight, viewWidth, v
32
32
  // through its runtime; an empty or unmeasurable root yields identity. This is the scene2d-fit transform the 2D
33
33
  // present pass applies before drawing the tree.
34
34
  export function computeScene2DFitTransform(out, scene2d, viewWidth, viewHeight) {
35
+ let contentX = 0;
36
+ let contentY = 0;
35
37
  let contentWidth = 0;
36
38
  let contentHeight = 0;
37
39
  if (scene2d.root !== null) {
38
40
  const runtime = getNodeRuntime(scene2d.root);
39
41
  if (runtime?.computeLocalBoundsRectangle !== undefined) {
42
+ _tempRectangle.x = 0;
43
+ _tempRectangle.y = 0;
40
44
  _tempRectangle.width = 0;
41
45
  _tempRectangle.height = 0;
42
46
  runtime.computeLocalBoundsRectangle(_tempRectangle, scene2d.root);
47
+ contentX = _tempRectangle.x;
48
+ contentY = _tempRectangle.y;
43
49
  contentWidth = _tempRectangle.width;
44
50
  contentHeight = _tempRectangle.height;
45
51
  }
@@ -73,8 +79,8 @@ export function computeScene2DFitTransform(out, scene2d, viewWidth, viewHeight)
73
79
  out.b = 0;
74
80
  out.c = 0;
75
81
  out.d = sy;
76
- out.tx = computeScene2DFitAlignX(contentWidth * sx, viewWidth, scene2d.align);
77
- out.ty = computeScene2DFitAlignY(contentHeight * sy, viewHeight, scene2d.align);
82
+ out.tx = computeScene2DFitAlignX(contentWidth * sx, viewWidth, scene2d.align) - contentX * sx;
83
+ out.ty = computeScene2DFitAlignY(contentHeight * sy, viewHeight, scene2d.align) - contentY * sy;
78
84
  }
79
85
  const _tempRectangle = createRectangle();
80
86
  //# sourceMappingURL=stageFit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"stageFit.js","sourceRoot":"","sources":["../src/stageFit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stageFit.js","sourceRoot":"","sources":["../src/stageFit.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/node",
3
- "version": "0.3.1-next.861.5a56d7a",
3
+ "version": "0.3.1-next.948.85d9f30",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,12 +38,13 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/adjustments": "0.3.1-next.861.5a56d7a",
42
- "@flighthq/entity": "0.3.1-next.861.5a56d7a",
43
- "@flighthq/geometry": "0.3.1-next.861.5a56d7a",
44
- "@flighthq/materials": "0.3.1-next.861.5a56d7a",
45
- "@flighthq/signals": "0.3.1-next.861.5a56d7a",
46
- "@flighthq/types": "0.3.1-next.861.5a56d7a"
41
+ "@flighthq/adjustments": "0.3.1-next.948.85d9f30",
42
+ "@flighthq/entity": "0.3.1-next.948.85d9f30",
43
+ "@flighthq/geometry": "0.3.1-next.948.85d9f30",
44
+ "@flighthq/materials": "0.3.1-next.948.85d9f30",
45
+ "@flighthq/math": "0.3.1-next.948.85d9f30",
46
+ "@flighthq/signals": "0.3.1-next.948.85d9f30",
47
+ "@flighthq/types": "0.3.1-next.948.85d9f30"
47
48
  },
48
49
  "devDependencies": {
49
50
  "typescript": "^5.3.0"
@@ -13,6 +13,8 @@ import {
13
13
  initTransform2DRuntimeTrait,
14
14
  initTransform2DTrait,
15
15
  invalidateNodeLocalTransform,
16
+ removeNodeChild,
17
+ setNodeEnabled,
16
18
  } from '@flighthq/node/contract';
17
19
  import type {
18
20
  HasBoundsRectangle,
@@ -120,9 +122,10 @@ describe('computeNodeBoundsRectangle', () => {
120
122
  it('should compute bounds relative to nested child', () => {
121
123
  const out = createRectangle();
122
124
  computeNodeBoundsRectangle(out, root, grandChild);
123
- expect(out.width).toBeGreaterThan(0);
124
- expect(out.height).toBeGreaterThan(0);
125
- // exact numbers depend on transforms
125
+ expect(out.x).toBeCloseTo(-100);
126
+ expect(out.y).toBeCloseTo(-100);
127
+ expect(out.width).toBeCloseTo(205);
128
+ expect(out.height).toBeCloseTo(205);
126
129
  });
127
130
 
128
131
  it('should account for scaling in parent transforms', () => {
@@ -187,6 +190,20 @@ describe('computeNodeBoundsRectangle', () => {
187
190
  computeNodeBoundsRectangle(out, child, root);
188
191
  expect(equalsRectangle(out, getNodeWorldBoundsRectangle(child))).toBe(true);
189
192
  });
193
+
194
+ it('removes a detached target transform from target-relative bounds', () => {
195
+ root.x = 40;
196
+ root.y = -25;
197
+ invalidateNodeLocalTransform(root);
198
+ const out = createRectangle();
199
+
200
+ computeNodeBoundsRectangle(out, child, root);
201
+
202
+ expect(out.x).toBeCloseTo(105);
203
+ expect(out.y).toBeCloseTo(105);
204
+ expect(out.width).toBeCloseTo(100);
205
+ expect(out.height).toBeCloseTo(100);
206
+ });
190
207
  });
191
208
 
192
209
  describe('computeNodeRootLocalBoundsRectangle', () => {
@@ -573,8 +590,71 @@ describe('getNodeWorldBoundsRectangle', () => {
573
590
  invalidateNodeLocalTransform(child);
574
591
 
575
592
  const bounds = getNodeWorldBoundsRectangle(parent);
576
- expect(bounds.width).toBeGreaterThan(10);
577
- expect(bounds.height).toBeGreaterThan(10);
593
+ expect(bounds).toMatchObject({ x: 0, y: 0, width: 300, height: 200 });
594
+ });
595
+
596
+ it('refreshes cached aggregate bounds when a child moves', () => {
597
+ const parent = createTestNode();
598
+ const child = createTestNode();
599
+ addNodeChild(parent, child);
600
+ setRectangle(getNodeLocalBoundsRectangle(parent) as Rectangle, 0, 0, 10, 10);
601
+ setRectangle(getNodeLocalBoundsRectangle(child) as Rectangle, 0, 0, 20, 20);
602
+ child.x = 30;
603
+ invalidateNodeLocalTransform(child);
604
+ expect(getNodeWorldBoundsRectangle(parent)).toMatchObject({ x: 0, y: 0, width: 50, height: 20 });
605
+
606
+ child.x = 80;
607
+ invalidateNodeLocalTransform(child);
608
+
609
+ expect(getNodeWorldBoundsRectangle(parent)).toMatchObject({ x: 0, y: 0, width: 100, height: 20 });
610
+ });
611
+
612
+ it('consults a descendant kind-owned bounds validity hook after the aggregate is cached', () => {
613
+ const parent = createTestNode();
614
+ const child = createTestNode();
615
+ const runtime = getEntityRuntime(child);
616
+ let input = { width: 20 };
617
+ let stampedInput = input;
618
+ runtime.computeLocalBoundsRectangle = (out: Rectangle) => {
619
+ setRectangle(out, 100, 0, input.width, 10);
620
+ stampedInput = input;
621
+ };
622
+ runtime.isLocalBoundsRectangleValid = () => stampedInput === input;
623
+ addNodeChild(parent, child);
624
+ setRectangle(getNodeLocalBoundsRectangle(parent) as Rectangle, 0, 0, 10, 10);
625
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(120);
626
+
627
+ input = { width: 50 };
628
+
629
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(150);
630
+ });
631
+
632
+ it('refreshes cached aggregate bounds when a child is removed', () => {
633
+ const parent = createTestNode();
634
+ const child = createTestNode();
635
+ addNodeChild(parent, child);
636
+ setRectangle(getNodeLocalBoundsRectangle(parent) as Rectangle, 0, 0, 10, 10);
637
+ setRectangle(getNodeLocalBoundsRectangle(child) as Rectangle, 100, 0, 200, 200);
638
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(300);
639
+
640
+ removeNodeChild(parent, child);
641
+
642
+ expect(getNodeWorldBoundsRectangle(parent)).toMatchObject({ x: 0, y: 0, width: 10, height: 10 });
643
+ });
644
+
645
+ it('refreshes cached aggregate bounds when a child is disabled or re-enabled', () => {
646
+ const parent = createTestNode();
647
+ const child = createTestNode();
648
+ addNodeChild(parent, child);
649
+ setRectangle(getNodeLocalBoundsRectangle(parent) as Rectangle, 0, 0, 10, 10);
650
+ setRectangle(getNodeLocalBoundsRectangle(child) as Rectangle, 100, 0, 200, 200);
651
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(300);
652
+
653
+ setNodeEnabled(child, false);
654
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(10);
655
+
656
+ setNodeEnabled(child, true);
657
+ expect(getNodeWorldBoundsRectangle(parent).width).toBe(300);
578
658
  });
579
659
 
580
660
  it('ignores an enabled child with zero-area world bounds', () => {
@@ -609,6 +689,74 @@ describe('setNodeHeight', () => {
609
689
  setNodeHeight(node, 100);
610
690
  expect(node.scaleY).toBe(0);
611
691
  });
692
+
693
+ it('keeps a finite scale when the current height is zero', () => {
694
+ const node = createTestNode();
695
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 10, 0);
696
+
697
+ setNodeHeight(node, 100);
698
+
699
+ expect(node.scaleY).toBe(1);
700
+ expect(Number.isFinite(node.scaleY)).toBe(true);
701
+ });
702
+
703
+ for (const [name, transform] of sizeRoundTripTransforms) {
704
+ it(`round-trips parent-space height through ${name}`, () => {
705
+ const parent = createTestNode();
706
+ const node = createTestNode();
707
+ addNodeChild(parent, node);
708
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 10, 20);
709
+ Object.assign(node, transform);
710
+ invalidateNodeLocalTransform(node);
711
+ const sign = Math.sign(node.scaleY);
712
+
713
+ setNodeHeight(node, 100);
714
+
715
+ expect(getNodeHeight(node)).toBeCloseTo(100, 10);
716
+ expect(Math.sign(node.scaleY)).toBe(sign);
717
+ });
718
+ }
719
+
720
+ it('declines an unsatisfiable height below the fixed x-axis contribution', () => {
721
+ const parent = createTestNode();
722
+ const node = createTestNode();
723
+ addNodeChild(parent, node);
724
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 10, 20);
725
+ node.rotation = 30;
726
+ invalidateNodeLocalTransform(node);
727
+ const scaleY = node.scaleY;
728
+
729
+ setNodeHeight(node, 4);
730
+
731
+ expect(node.scaleY).toBe(scaleY);
732
+ });
733
+
734
+ it('does not mutate at a singular rotation and still solves near it', () => {
735
+ const singularParent = createTestNode();
736
+ const singular = createTestNode();
737
+ addNodeChild(singularParent, singular);
738
+ setRectangle(getNodeLocalBoundsRectangle(singular) as Rectangle, 0, 0, 10, 20);
739
+ singular.rotation = 90;
740
+ singular.scaleY = 2;
741
+ invalidateNodeLocalTransform(singular);
742
+
743
+ setNodeHeight(singular, 50);
744
+
745
+ expect(singular.scaleY).toBe(2);
746
+ expect(Number.isFinite(singular.scaleY)).toBe(true);
747
+
748
+ const nearParent = createTestNode();
749
+ const near = createTestNode();
750
+ addNodeChild(nearParent, near);
751
+ setRectangle(getNodeLocalBoundsRectangle(near) as Rectangle, 0, 0, 10, 20);
752
+ near.rotation = 89.999;
753
+ invalidateNodeLocalTransform(near);
754
+
755
+ setNodeHeight(near, 50);
756
+
757
+ expect(Number.isFinite(near.scaleY)).toBe(true);
758
+ expect(getNodeHeight(near)).toBeCloseTo(50, 8);
759
+ });
612
760
  });
613
761
 
614
762
  describe('setNodeWidth', () => {
@@ -628,6 +776,74 @@ describe('setNodeWidth', () => {
628
776
  setNodeWidth(node, 100);
629
777
  expect(node.scaleX).toBe(0);
630
778
  });
779
+
780
+ it('keeps a finite scale when the current width is zero', () => {
781
+ const node = createTestNode();
782
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 0, 10);
783
+
784
+ setNodeWidth(node, 100);
785
+
786
+ expect(node.scaleX).toBe(1);
787
+ expect(Number.isFinite(node.scaleX)).toBe(true);
788
+ });
789
+
790
+ for (const [name, transform] of sizeRoundTripTransforms) {
791
+ it(`round-trips parent-space width through ${name}`, () => {
792
+ const parent = createTestNode();
793
+ const node = createTestNode();
794
+ addNodeChild(parent, node);
795
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 10, 20);
796
+ Object.assign(node, transform);
797
+ invalidateNodeLocalTransform(node);
798
+ const sign = Math.sign(node.scaleX);
799
+
800
+ setNodeWidth(node, 100);
801
+
802
+ expect(getNodeWidth(node)).toBeCloseTo(100, 10);
803
+ expect(Math.sign(node.scaleX)).toBe(sign);
804
+ });
805
+ }
806
+
807
+ it('declines an unsatisfiable width below the fixed y-axis contribution', () => {
808
+ const parent = createTestNode();
809
+ const node = createTestNode();
810
+ addNodeChild(parent, node);
811
+ setRectangle(getNodeLocalBoundsRectangle(node) as Rectangle, 0, 0, 10, 20);
812
+ node.rotation = 30;
813
+ invalidateNodeLocalTransform(node);
814
+ const scaleX = node.scaleX;
815
+
816
+ setNodeWidth(node, 5);
817
+
818
+ expect(node.scaleX).toBe(scaleX);
819
+ });
820
+
821
+ it('does not mutate at a singular rotation and still solves near it', () => {
822
+ const singularParent = createTestNode();
823
+ const singular = createTestNode();
824
+ addNodeChild(singularParent, singular);
825
+ setRectangle(getNodeLocalBoundsRectangle(singular) as Rectangle, 0, 0, 10, 20);
826
+ singular.rotation = 90;
827
+ singular.scaleX = 2;
828
+ invalidateNodeLocalTransform(singular);
829
+
830
+ setNodeWidth(singular, 50);
831
+
832
+ expect(singular.scaleX).toBe(2);
833
+ expect(Number.isFinite(singular.scaleX)).toBe(true);
834
+
835
+ const nearParent = createTestNode();
836
+ const near = createTestNode();
837
+ addNodeChild(nearParent, near);
838
+ setRectangle(getNodeLocalBoundsRectangle(near) as Rectangle, 0, 0, 10, 20);
839
+ near.rotation = 89.999;
840
+ invalidateNodeLocalTransform(near);
841
+
842
+ setNodeWidth(near, 50);
843
+
844
+ expect(Number.isFinite(near.scaleX)).toBe(true);
845
+ expect(getNodeWidth(near)).toBeCloseTo(50, 8);
846
+ });
631
847
  });
632
848
 
633
849
  function cloneAndInvalidateRect(rect: Rectangle): Rectangle {
@@ -642,4 +858,11 @@ function invalidateRect(rect: Rectangle | null): void {
642
858
 
643
859
  type TestNode = Node<HasTransform2D & HasBoundsRectangle> & HasTransform2D & HasBoundsRectangle;
644
860
 
861
+ const sizeRoundTripTransforms = [
862
+ ['rotation', { rotation: 30, scaleX: 1, scaleY: 1, skewX: 0, skewY: 0 }],
863
+ ['skew and non-uniform scale', { rotation: 10, scaleX: 0.7, scaleY: 2.3, skewX: 25, skewY: -15 }],
864
+ ['mirrored x scale', { rotation: -25, scaleX: -1.4, scaleY: 0.6, skewX: -10, skewY: 20 }],
865
+ ['mirrored y scale', { rotation: 40, scaleX: 1.8, scaleY: -1.2, skewX: 12, skewY: -18 }],
866
+ ] as const;
867
+
645
868
  const TestKind = 'Test';
@@ -1,7 +1,7 @@
1
- import type { HasAppearance } from '@flighthq/types/contract';
1
+ import type { HasAppearance, HasAppearanceRuntime, NodeRuntime } from '@flighthq/types/contract';
2
2
 
3
- import { initAppearanceTrait } from './hasAppearance';
4
- import { createNode } from './node';
3
+ import { initAppearanceRuntimeTrait, initAppearanceTrait } from './hasAppearance';
4
+ import { createNode, createNodeRuntime } from './node';
5
5
 
6
6
  const TestKind = 'Test';
7
7
 
@@ -10,6 +10,36 @@ function makeTarget(): HasAppearance {
10
10
  return node;
11
11
  }
12
12
 
13
+ describe('initAppearanceRuntimeTrait', () => {
14
+ let runtime: NodeRuntime<HasAppearance> & HasAppearanceRuntime;
15
+
16
+ beforeEach(() => {
17
+ runtime = createNodeRuntime() as NodeRuntime<HasAppearance> & HasAppearanceRuntime;
18
+ });
19
+
20
+ it('initializes default values', () => {
21
+ initAppearanceRuntimeTrait(runtime);
22
+
23
+ expect(runtime.worldAlpha).toBeNull();
24
+ expect(runtime.worldAlphaUsingAppearanceId).toStrictEqual(-1);
25
+ expect(runtime.worldAlphaUsingParentAppearanceId).toStrictEqual(-1);
26
+ expect(runtime.worldAppearanceId).toStrictEqual(0);
27
+ });
28
+
29
+ it('resets a resolved cache back to the unresolved state', () => {
30
+ runtime.worldAlpha = 0.25;
31
+ runtime.worldAlphaUsingAppearanceId = 7;
32
+ runtime.worldAlphaUsingParentAppearanceId = 9;
33
+ runtime.worldAppearanceId = 11;
34
+ initAppearanceRuntimeTrait(runtime);
35
+
36
+ expect(runtime.worldAlpha).toBeNull();
37
+ expect(runtime.worldAlphaUsingAppearanceId).toStrictEqual(-1);
38
+ expect(runtime.worldAlphaUsingParentAppearanceId).toStrictEqual(-1);
39
+ expect(runtime.worldAppearanceId).toStrictEqual(0);
40
+ });
41
+ });
42
+
13
43
  describe('initAppearanceTrait', () => {
14
44
  it('sets default values when called with no options', () => {
15
45
  const target = makeTarget();
@@ -34,6 +34,8 @@ describe('initTransform2DTrait', () => {
34
34
  it('initializes default values', () => {
35
35
  initTransform2DTrait(node);
36
36
 
37
+ expect(node.pivotX).toStrictEqual(0);
38
+ expect(node.pivotY).toStrictEqual(0);
37
39
  expect(node.rotation).toStrictEqual(0);
38
40
  expect(node.scaleX).toStrictEqual(1);
39
41
  expect(node.scaleY).toStrictEqual(1);
@@ -45,6 +47,8 @@ describe('initTransform2DTrait', () => {
45
47
 
46
48
  it('allows pre-defined values', () => {
47
49
  const base = {
50
+ pivotX: 4,
51
+ pivotY: 8,
48
52
  scaleX: 2,
49
53
  scaleY: 3,
50
54
  skewX: 15,
@@ -54,6 +58,8 @@ describe('initTransform2DTrait', () => {
54
58
  y: 200,
55
59
  };
56
60
  initTransform2DTrait(node, base);
61
+ expect(node.pivotX).toStrictEqual(base.pivotX);
62
+ expect(node.pivotY).toStrictEqual(base.pivotY);
57
63
  expect(node.scaleX).toStrictEqual(base.scaleX);
58
64
  expect(node.scaleY).toStrictEqual(base.scaleY);
59
65
  expect(node.skewX).toStrictEqual(base.skewX);
@@ -1,13 +1,19 @@
1
1
  import { createQuaternion, createVector3 } from '@flighthq/geometry/contract';
2
- import type { HasTransform3D, HasTransform3DRuntime } from '@flighthq/types/contract';
3
- import { describe, expect, it } from 'vitest';
2
+ import type { HasTransform3D, HasTransform3DRuntime, Node, NodeRuntime } from '@flighthq/types/contract';
4
3
 
5
4
  import { initTransform3DRuntimeTrait, initTransform3DTrait } from './hasTransform3d';
5
+ import { createNode, createNodeRuntime } from './node';
6
6
 
7
7
  describe('initTransform3DRuntimeTrait', () => {
8
+ let runtime: NodeRuntime<HasTransform3D> & HasTransform3DRuntime;
9
+
10
+ beforeEach(() => {
11
+ runtime = createNodeRuntime() as NodeRuntime<HasTransform3D> & HasTransform3DRuntime;
12
+ });
13
+
8
14
  it('nulls the matrix caches and clears the detached flag', () => {
9
- const runtime = {} as HasTransform3DRuntime;
10
15
  initTransform3DRuntimeTrait(runtime);
16
+
11
17
  expect(runtime.localMatrix4).toBeNull();
12
18
  expect(runtime.worldMatrix4).toBeNull();
13
19
  expect(runtime.localMatrix4Detached).toBe(false);
@@ -15,22 +21,48 @@ describe('initTransform3DRuntimeTrait', () => {
15
21
  });
16
22
 
17
23
  describe('initTransform3DTrait', () => {
24
+ let node: HasTransform3D;
25
+
26
+ beforeEach(() => {
27
+ node = createNode(NodeTestKind) as Node<HasTransform3D> & HasTransform3D;
28
+ });
29
+
18
30
  it('defaults to identity position/rotation/scale', () => {
19
- const node = {} as HasTransform3D;
20
31
  initTransform3DTrait(node);
32
+
21
33
  expect(node.position).toMatchObject({ x: 0, y: 0, z: 0 });
22
34
  expect(node.rotation).toMatchObject({ x: 0, y: 0, z: 0, w: 1 });
23
35
  expect(node.scale).toMatchObject({ x: 1, y: 1, z: 1 });
24
36
  });
25
37
 
26
38
  it('accepts existing position/rotation/scale', () => {
27
- const node = {} as HasTransform3D;
28
39
  const position = createVector3(7, 0, 0);
29
40
  const rotation = createQuaternion();
30
41
  const scale = createVector3(2, 2, 2);
31
42
  initTransform3DTrait(node, { position, rotation, scale });
32
- expect(node.position).toBe(position);
33
- expect(node.rotation).toBe(rotation);
34
- expect(node.scale).toBe(scale);
43
+
44
+ expect(node.position).toMatchObject({ x: 7, y: 0, z: 0 });
45
+ expect(node.rotation).toMatchObject({ x: 0, y: 0, z: 0, w: 1 });
46
+ expect(node.scale).toMatchObject({ x: 2, y: 2, z: 2 });
47
+ });
48
+
49
+ it('copies out of the options object so two nodes never share storage', () => {
50
+ const options = { position: createVector3(1, 2, 3), rotation: createQuaternion(), scale: createVector3(2, 2, 2) };
51
+ const second = createNode(NodeTestKind) as Node<HasTransform3D> & HasTransform3D;
52
+ initTransform3DTrait(node, options);
53
+ initTransform3DTrait(second, options);
54
+
55
+ node.position.x = 999;
56
+ node.scale.y = 999;
57
+ node.rotation.w = 0;
58
+
59
+ expect(second.position.x).toBe(1);
60
+ expect(second.scale.y).toBe(2);
61
+ expect(second.rotation.w).toBe(1);
62
+ expect(options.position.x).toBe(1);
63
+ expect(options.scale.y).toBe(2);
64
+ expect(options.rotation.w).toBe(1);
35
65
  });
36
66
  });
67
+
68
+ const NodeTestKind = 'NodeTest';