@flighthq/scene2d 0.3.0-next.906.07cea63 → 0.3.1-next.209.43ef1bc

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.
@@ -1,9 +1,8 @@
1
- export * from './bitmap';
1
+ export * from './sprite';
2
2
  export * from './displayContainer';
3
3
  export * from './displayObject';
4
4
  export * from './displayObjectAnimation';
5
5
  export * from './htmlView';
6
- export * from './renderTargetNode2D';
7
6
  export * from './scene2d';
8
- export * from './video';
7
+ export * from './sceneKindUsage';
9
8
  //# sourceMappingURL=contract.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
package/dist/contract.js CHANGED
@@ -1,9 +1,8 @@
1
- export * from './bitmap';
1
+ export * from './sprite';
2
2
  export * from './displayContainer';
3
3
  export * from './displayObject';
4
4
  export * from './displayObjectAnimation';
5
5
  export * from './htmlView';
6
- export * from './renderTargetNode2D';
7
6
  export * from './scene2d';
8
- export * from './video';
7
+ export * from './sceneKindUsage';
9
8
  //# sourceMappingURL=contract.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { ClipRegion, Node2D, Node2DDataFactory, Node2DRuntime, Node2DRuntimeFactory, Kind, MethodsOf, NodeAny, PartialNode } from '@flighthq/types/contract';
2
2
  export declare function createNode2D<R extends Node2DRuntime>(kind: Kind, obj?: Readonly<PartialNode<Node2D>>, createData?: Node2DDataFactory, createNode2DRuntimeFactory?: Node2DRuntimeFactory<R>): Node2D;
3
- export declare function createNode2DRuntime(methods?: Readonly<Partial<MethodsOf<Node2DRuntime>>>): Node2DRuntime;
3
+ export declare function createNode2DRuntime(methods?: Readonly<Partial<MethodsOf<Node2DRuntime> & Pick<Node2DRuntime, 'isLocalBoundsRectangleValid'>>>): Node2DRuntime;
4
4
  export declare function getNode2DRuntime(source: Readonly<Node2D>): Readonly<Node2DRuntime>;
5
5
  export declare function isNode2D(node: NodeAny): node is Node2D;
6
6
  export declare function setNode2DClip(source: Node2D, value: ClipRegion | null): void;
@@ -1 +1 @@
1
- {"version":3,"file":"displayObject.d.ts","sourceRoot":"","sources":["../src/displayObject.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,UAAU,EACV,MAAM,EACN,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,IAAI,EACJ,SAAS,EACT,OAAO,EAEP,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAClD,IAAI,EAAE,IAAI,EACV,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EACnC,UAAU,CAAC,EAAE,iBAAiB,EAC9B,0BAA0B,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GACnD,MAAM,CAcR;AAED,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAOxG;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,CAElF;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAG5E;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"displayObject.d.ts","sourceRoot":"","sources":["../src/displayObject.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACV,UAAU,EACV,MAAM,EACN,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,IAAI,EACJ,SAAS,EACT,OAAO,EAEP,WAAW,EACZ,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAClD,IAAI,EAAE,IAAI,EACV,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,EACnC,UAAU,CAAC,EAAE,iBAAiB,EAC9B,0BAA0B,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC,GACnD,MAAM,CAcR;AAED,wBAAgB,mBAAmB,CACjC,OAAO,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,aAAa,EAAE,6BAA6B,CAAC,CAAC,CAAC,GACzG,aAAa,CAOf;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,CAElF;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAEtD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,GAAG,IAAI,CAG5E;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"displayObject.js","sourceRoot":"","sources":["../src/displayObject.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,aAAa,EACb,iBAAiB,EACjB,2BAA2B,EAC3B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAajC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,UAAU,YAAY,CAC1B,IAAU,EACV,GAAmC,EACnC,UAA8B,EAC9B,0BAAoD;IAEpD,MAAM,GAAG,GAAG,UAAU,CACpB,IAAI,EACJ,GAAG,EACH,UAAU,EACV,0BAA0B,IAAK,mBAAwD,CAC9E,CAAC;IACZ,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/B,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACnC,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7B,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAqD;IACvF,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAkB,CAAC;IACxD,GAAG,CAAC,MAAM,GAAG,eAAe,CAAC;IAC7B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;IACnB,2BAA2B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1C,+BAA+B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,OAAO,cAAc,CAAC,MAAM,CAAkB,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAwB;IACpE,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"displayObject.js","sourceRoot":"","sources":["../src/displayObject.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,+BAA+B,EAC/B,wBAAwB,EACxB,aAAa,EACb,iBAAiB,EACjB,2BAA2B,EAC3B,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAajC,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAE3D,MAAM,UAAU,YAAY,CAC1B,IAAU,EACV,GAAmC,EACnC,UAA8B,EAC9B,0BAAoD;IAEpD,MAAM,GAAG,GAAG,UAAU,CACpB,IAAI,EACJ,GAAG,EACH,UAAU,EACV,0BAA0B,IAAK,mBAAwD,CAC9E,CAAC;IACZ,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/B,wBAAwB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACnC,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC9B,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC7B,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC5B,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAA0G;IAE1G,MAAM,GAAG,GAAG,iBAAiB,CAAC,OAAO,CAAkB,CAAC;IACxD,GAAG,CAAC,MAAM,GAAG,eAAe,CAAC;IAC7B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;IACnB,2BAA2B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1C,+BAA+B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC9C,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,OAAO,cAAc,CAAC,MAAM,CAAkB,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,IAAa;IACpC,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,eAAe,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,KAAwB;IACpE,MAAM,CAAC,IAAI,GAAG,KAAK,CAAC;IACpB,wBAAwB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC;AAED,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { applyAnimationClipToNode2D, computeBitmapLocalBoundsRectangle, computeHtmlViewLocalBoundsRectangle, computeVideoLocalBoundsRectangle, createBitmap, createDisplayObject, createHtmlView, createNode2D, createRenderTargetNode2D, createScene2D, createVideo, enableScene2DSignals, getScene2DRoot, getScene2DSignals, isNode2D, setBitmapImage, setHtmlViewSize, setNode2DClip, setRenderTargetNode2DSize, setScene2DSize, setVideoSmoothing, setVideoSource, } from './contract';
1
+ export { applyAnimationClipToNode2D, cloneSprite, computeSpriteLocalBoundsRectangle, computeHtmlViewLocalBoundsRectangle, createSprite, createDisplayObject, createHtmlView, createNode2D, createScene2D, enableScene2DSignals, getScene2DRoot, getScene2DSignals, isNode2D, setHtmlViewSize, setNode2DClip, setScene2DSize, } from './contract';
2
2
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,iCAAiC,EACjC,mCAAmC,EACnC,gCAAgC,EAChC,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,EACb,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,iCAAiC,EACjC,mCAAmC,EACnC,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { applyAnimationClipToNode2D, computeBitmapLocalBoundsRectangle, computeHtmlViewLocalBoundsRectangle, computeVideoLocalBoundsRectangle, createBitmap, createDisplayObject, createHtmlView, createNode2D, createRenderTargetNode2D, createScene2D, createVideo, enableScene2DSignals, getScene2DRoot, getScene2DSignals, isNode2D, setBitmapImage, setHtmlViewSize, setNode2DClip, setRenderTargetNode2DSize, setScene2DSize, setVideoSmoothing, setVideoSource, } from './contract';
1
+ export { applyAnimationClipToNode2D, cloneSprite, computeSpriteLocalBoundsRectangle, computeHtmlViewLocalBoundsRectangle, createSprite, createDisplayObject, createHtmlView, createNode2D, createScene2D, enableScene2DSignals, getScene2DRoot, getScene2DSignals, isNode2D, setHtmlViewSize, setNode2DClip, setScene2DSize, } from './contract';
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,iCAAiC,EACjC,mCAAmC,EACnC,gCAAgC,EAChC,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,wBAAwB,EACxB,aAAa,EACb,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,aAAa,EACb,yBAAyB,EACzB,cAAc,EACd,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,EAC1B,WAAW,EACX,iCAAiC,EACjC,mCAAmC,EACnC,YAAY,EACZ,mBAAmB,EACnB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,eAAe,EACf,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Scene2D, Scene2DKindUsage } from '@flighthq/types/contract';
2
+ export declare function createScene2DKindUsage(): Scene2DKindUsage;
3
+ export declare function getScene2DKindUsage(out: Scene2DKindUsage, scene: Readonly<Scene2D>): void;
4
+ //# sourceMappingURL=sceneKindUsage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sceneKindUsage.d.ts","sourceRoot":"","sources":["../src/sceneKindUsage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAU,OAAO,EAAE,gBAAgB,EAAqB,MAAM,0BAA0B,CAAC;AAKrG,wBAAgB,sBAAsB,IAAI,gBAAgB,CAEzD;AASD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,gBAAgB,EAAE,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,IAAI,CAmCzF"}
@@ -0,0 +1,61 @@
1
+ import { forEachNodeDescendant } from '@flighthq/node/contract';
2
+ import { BlendMode } from '@flighthq/types/contract';
3
+ // Allocates an empty usage record. Separate from the walk so a caller can reuse one across scenes or
4
+ // frames without reallocating four arrays.
5
+ export function createScene2DKindUsage() {
6
+ return { blendModes: [], materialKinds: [], nodeKinds: [], shapeCommandKeys: [] };
7
+ }
8
+ // Clears `out`, then fills it with every kind this scene uses. One walk, no registry, no backend, no
9
+ // prose — it reads the fields the scene graph already carries, so it cannot itself be the thing you
10
+ // forgot to wire.
11
+ //
12
+ // This answers only WHAT IS IN THE SCENE. Whether anything is registered to draw it is a question for
13
+ // the package that owns the registry: each backend checks its own renderer, material, and shape-command
14
+ // registries. Keeping those answers out of here is what lets a scene stay ignorant of rendering.
15
+ export function getScene2DKindUsage(out, scene) {
16
+ out.blendModes.length = 0;
17
+ out.materialKinds.length = 0;
18
+ out.nodeKinds.length = 0;
19
+ out.shapeCommandKeys.length = 0;
20
+ const visit = (node) => {
21
+ addScene2DUsedKind(out.nodeKinds, node.kind);
22
+ // An unset node carries null and inherits its parent's mode; Normal is what every backend
23
+ // composites with no registration at all. Reporting either would send a caller looking for a
24
+ // realization it never needs, so only an explicit non-Normal mode counts as used.
25
+ if (node.blendMode !== null && node.blendMode !== BlendMode.Normal) {
26
+ addScene2DUsedKind(out.blendModes, node.blendMode);
27
+ }
28
+ if (node.material !== null)
29
+ addScene2DUsedKind(out.materialKinds, node.material.kind);
30
+ // Structural, like isMesh: any node family whose data carries a command stream is walked, including
31
+ // a custom kind, without a per-kind table that would drift as families are added. Shape, MorphShape
32
+ // and Scale9Shape all record into the same flat [key, argCount, ...args] buffer.
33
+ const commands = node.data?.commands;
34
+ if (commands === undefined)
35
+ return;
36
+ let i = 0;
37
+ while (i < commands.length) {
38
+ addScene2DUsedKind(out.shapeCommandKeys, commands[i]);
39
+ i += commands[i + 1] + 2;
40
+ }
41
+ };
42
+ visit(scene.root);
43
+ // forEachNodeDescendant yields Node<Node2DTraits>; the cast restores the trait fields the walk
44
+ // generic drops, which the visitor reads structurally.
45
+ forEachNodeDescendant(scene.root, (node) => visit(node));
46
+ out.blendModes.sort();
47
+ out.materialKinds.sort();
48
+ out.nodeKinds.sort();
49
+ out.shapeCommandKeys.sort();
50
+ }
51
+ // Linear scan rather than a Set: these lists are the handful of distinct kinds a document uses, where
52
+ // scanning beats allocating four Sets per walk, and it keeps the result a plain array a C port can hold
53
+ // without a hash container.
54
+ function addScene2DUsedKind(kinds, kind) {
55
+ for (let i = 0; i < kinds.length; i++) {
56
+ if (kinds[i] === kind)
57
+ return;
58
+ }
59
+ kinds.push(kind);
60
+ }
61
+ //# sourceMappingURL=sceneKindUsage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sceneKindUsage.js","sourceRoot":"","sources":["../src/sceneKindUsage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,qGAAqG;AACrG,2CAA2C;AAC3C,MAAM,UAAU,sBAAsB;IACpC,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC;AACpF,CAAC;AAED,qGAAqG;AACrG,oGAAoG;AACpG,kBAAkB;AAClB,EAAE;AACF,sGAAsG;AACtG,wGAAwG;AACxG,iGAAiG;AACjG,MAAM,UAAU,mBAAmB,CAAC,GAAqB,EAAE,KAAwB;IACjF,GAAG,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,GAAG,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC;IAC7B,GAAG,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACzB,GAAG,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAEhC,MAAM,KAAK,GAAG,CAAC,IAAsB,EAAQ,EAAE;QAC7C,kBAAkB,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,0FAA0F;QAC1F,6FAA6F;QAC7F,kFAAkF;QAClF,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,IAAI,CAAC,SAAS,KAAK,SAAS,CAAC,MAAM,EAAE,CAAC;YACnE,kBAAkB,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,CAAC;QACD,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI;YAAE,kBAAkB,CAAC,GAAG,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACtF,oGAAoG;QACpG,oGAAoG;QACpG,iFAAiF;QACjF,MAAM,QAAQ,GAAI,IAAI,CAAC,IAA6E,EAAE,QAAQ,CAAC;QAC/G,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO;QACnC,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;YAC3B,kBAAkB,CAAC,GAAG,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC,CAAW,CAAC,CAAC;YAChE,CAAC,IAAK,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAY,GAAG,CAAC,CAAC;QACvC,CAAC;IACH,CAAC,CAAC;IACF,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClB,+FAA+F;IAC/F,uDAAuD;IACvD,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAwB,CAAC,CAAC,CAAC;IAE7E,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IACtB,GAAG,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IACzB,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACrB,GAAG,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;AAC9B,CAAC;AAED,sGAAsG;AACtG,wGAAwG;AACxG,4BAA4B;AAC5B,SAAS,kBAAkB,CAAC,KAAe,EAAE,IAAY;IACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI;YAAE,OAAO;IAChC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { Node, PartialNode, Rectangle, Renderable, RendererData, RenderState, Sprite, SpriteData, SpriteRuntime } from '@flighthq/types/contract';
2
+ export declare function cloneSprite(source: Readonly<Sprite>): Sprite;
3
+ export declare function computeSpriteLocalBoundsRectangle(out: Rectangle, source: Readonly<Node>): void;
4
+ export declare function createSprite(obj?: Readonly<PartialNode<Sprite>>): Sprite;
5
+ export declare function createSpriteData(data?: Readonly<Partial<SpriteData>>): SpriteData;
6
+ export declare function createSpriteRendererData(_state: RenderState, source: Renderable): RendererData;
7
+ export declare function createSpriteRuntime(): SpriteRuntime;
8
+ export declare function getSpriteRuntime(source: Readonly<Sprite>): Readonly<SpriteRuntime>;
9
+ export declare function isSpriteRendererDirty(_state: RenderState, source: Renderable, rendererData: RendererData | null): boolean;
10
+ //# sourceMappingURL=sprite.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite.d.ts","sourceRoot":"","sources":["../src/sprite.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,IAAI,EACJ,WAAW,EACX,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,MAAM,EACN,UAAU,EACV,aAAa,EAEd,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,MAAM,CAE5D;AAED,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAQ9F;AAED,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAExE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,UAAU,CAIjF;AAID,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,GAAG,YAAY,CAG9F;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAKnD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,CAElF;AAID,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,YAAY,GAAG,IAAI,GAChC,OAAO,CAST"}
package/dist/sprite.js ADDED
@@ -0,0 +1,63 @@
1
+ import { createEntity } from '@flighthq/entity/contract';
2
+ import { getTextureHeight, getTextureWidth } from '@flighthq/texture/contract';
3
+ import { SpriteKind } from '@flighthq/types/contract';
4
+ import { createNode2D, createNode2DRuntime, getNode2DRuntime } from './displayObject';
5
+ export function cloneSprite(source) {
6
+ return createSprite({ data: { texture: source.data.texture } });
7
+ }
8
+ export function computeSpriteLocalBoundsRectangle(out, source) {
9
+ const sprite = source;
10
+ const texture = sprite.data.texture;
11
+ out.width = texture === null ? 0 : Math.max(0, getTextureWidth(texture)) * Math.abs(texture.uvScale.x);
12
+ out.height = texture === null ? 0 : Math.max(0, getTextureHeight(texture)) * Math.abs(texture.uvScale.y);
13
+ const runtime = getNode2DRuntime(sprite);
14
+ runtime.localBoundsTexture = texture;
15
+ runtime.localBoundsTextureVersion = texture?.version ?? -1;
16
+ }
17
+ export function createSprite(obj) {
18
+ return createNode2D(SpriteKind, obj, createSpriteData, createSpriteRuntime);
19
+ }
20
+ export function createSpriteData(data) {
21
+ return {
22
+ texture: data?.texture ?? null,
23
+ };
24
+ }
25
+ // Creates the per-state identity stamp used by a Sprite renderer's optional dirty hook. The data is
26
+ // attached to that state's render proxy, so separate render pipelines compare independently.
27
+ export function createSpriteRendererData(_state, source) {
28
+ const texture = source.data.texture;
29
+ return createEntity({ textureIdentity: texture, textureVersion: texture?.version ?? -1 });
30
+ }
31
+ export function createSpriteRuntime() {
32
+ const runtime = createNode2DRuntime(defaultMethods);
33
+ runtime.localBoundsTexture = null;
34
+ runtime.localBoundsTextureVersion = -1;
35
+ return runtime;
36
+ }
37
+ export function getSpriteRuntime(source) {
38
+ return getNode2DRuntime(source);
39
+ }
40
+ // Detects Texture identity/version changes before requiresInvalidation can skip a Sprite. Each
41
+ // backend opts into this through its registered renderer; the generic walk never knows SpriteKind.
42
+ export function isSpriteRendererDirty(_state, source, rendererData) {
43
+ if (rendererData === null)
44
+ return false;
45
+ const data = rendererData;
46
+ const texture = source.data.texture;
47
+ const version = texture?.version ?? -1;
48
+ const dirty = data.textureIdentity !== texture || data.textureVersion !== version;
49
+ data.textureIdentity = texture;
50
+ data.textureVersion = version;
51
+ return dirty;
52
+ }
53
+ function isSpriteLocalBoundsRectangleValid(source) {
54
+ const sprite = source;
55
+ const runtime = getNode2DRuntime(sprite);
56
+ const texture = sprite.data.texture;
57
+ return runtime.localBoundsTexture === texture && runtime.localBoundsTextureVersion === (texture?.version ?? -1);
58
+ }
59
+ const defaultMethods = {
60
+ computeLocalBoundsRectangle: computeSpriteLocalBoundsRectangle,
61
+ isLocalBoundsRectangleValid: isSpriteLocalBoundsRectangleValid,
62
+ };
63
+ //# sourceMappingURL=sprite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sprite.js","sourceRoot":"","sources":["../src/sprite.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,8 @@
1
1
  {
2
2
  "name": "@flighthq/scene2d",
3
- "version": "0.3.0-next.906.07cea63",
3
+ "version": "0.3.1-next.209.43ef1bc",
4
+ "author": "Joshua Granick and other contributors",
5
+ "license": "MIT",
4
6
  "repository": {
5
7
  "type": "git",
6
8
  "url": "https://github.com/flighthq/flight.git",
@@ -36,14 +38,15 @@
36
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
37
39
  },
38
40
  "dependencies": {
39
- "@flighthq/adjustments": "0.3.0-next.906.07cea63",
40
- "@flighthq/animation": "0.3.0-next.906.07cea63",
41
- "@flighthq/entity": "0.3.0-next.906.07cea63",
42
- "@flighthq/geometry": "0.3.0-next.906.07cea63",
43
- "@flighthq/materials": "0.3.0-next.906.07cea63",
44
- "@flighthq/node": "0.3.0-next.906.07cea63",
45
- "@flighthq/signals": "0.3.0-next.906.07cea63",
46
- "@flighthq/types": "0.3.0-next.906.07cea63"
41
+ "@flighthq/adjustments": "0.3.1-next.209.43ef1bc",
42
+ "@flighthq/animation": "0.3.1-next.209.43ef1bc",
43
+ "@flighthq/entity": "0.3.1-next.209.43ef1bc",
44
+ "@flighthq/geometry": "0.3.1-next.209.43ef1bc",
45
+ "@flighthq/materials": "0.3.1-next.209.43ef1bc",
46
+ "@flighthq/node": "0.3.1-next.209.43ef1bc",
47
+ "@flighthq/signals": "0.3.1-next.209.43ef1bc",
48
+ "@flighthq/texture": "0.3.1-next.209.43ef1bc",
49
+ "@flighthq/types": "0.3.1-next.209.43ef1bc"
47
50
  },
48
51
  "devDependencies": {
49
52
  "typescript": "^5.3.0"
@@ -0,0 +1,119 @@
1
+ import { createUnlitMaterial } from '@flighthq/materials/contract';
2
+ import { addNodeChild } from '@flighthq/node/contract';
3
+ import type { Node2D, Node2DData, ShapeCommandToken } from '@flighthq/types/contract';
4
+ import { BlendMode, DisplayObjectKind, HtmlViewKind } from '@flighthq/types/contract';
5
+ import { describe, expect, it } from 'vitest';
6
+
7
+ import { createDisplayObject } from './displayObject';
8
+ import { createHtmlView } from './htmlView';
9
+ import { createScene2D } from './scene2d';
10
+ import { createScene2DKindUsage, getScene2DKindUsage } from './sceneKindUsage';
11
+
12
+ // The walk detects a command stream structurally — any node whose `data` carries `commands` — rather
13
+ // than by node kind, so the tests record streams directly. That also keeps @flighthq/shape out of this
14
+ // package's dependencies, which it could not take anyway since shape depends on scene2d.
15
+ function shapeLikeNode(...commands: ShapeCommandToken[]): Node2D {
16
+ const node = createDisplayObject();
17
+ node.data = { commands } as unknown as Node2DData;
18
+ return node;
19
+ }
20
+
21
+ function usageOf(build: (root: Node2D) => void) {
22
+ const scene = createScene2D();
23
+ build(scene.root);
24
+ const usage = createScene2DKindUsage();
25
+ getScene2DKindUsage(usage, scene);
26
+ return usage;
27
+ }
28
+
29
+ describe('createScene2DKindUsage', () => {
30
+ it('starts empty so a caller can reuse one record across scenes', () => {
31
+ expect(createScene2DKindUsage()).toEqual({
32
+ blendModes: [],
33
+ materialKinds: [],
34
+ nodeKinds: [],
35
+ shapeCommandKeys: [],
36
+ });
37
+ });
38
+ });
39
+
40
+ describe('getScene2DKindUsage', () => {
41
+ it('collects node kinds across the tree, deduped and sorted', () => {
42
+ const usage = usageOf((root) => {
43
+ addNodeChild(root, createHtmlView());
44
+ addNodeChild(root, createHtmlView());
45
+ addNodeChild(root, createDisplayObject());
46
+ });
47
+ expect(usage.nodeKinds).toEqual([DisplayObjectKind, HtmlViewKind]);
48
+ });
49
+
50
+ it('walks a nested child, not just the root generation', () => {
51
+ const usage = usageOf((root) => {
52
+ const group = createDisplayObject();
53
+ addNodeChild(group, createHtmlView());
54
+ addNodeChild(root, group);
55
+ });
56
+ expect(usage.nodeKinds).toContain(HtmlViewKind);
57
+ });
58
+
59
+ it('reads the command keys out of a recorded stream', () => {
60
+ const usage = usageOf((root) => {
61
+ addNodeChild(root, shapeLikeNode('beginFill', 2, 0xff0000, 1, 'drawRectangle', 4, 0, 0, 10, 10, 'endFill', 0));
62
+ });
63
+ expect(usage.shapeCommandKeys).toEqual(['beginFill', 'drawRectangle', 'endFill']);
64
+ });
65
+
66
+ it('dedupes a command key repeated within one stream and across nodes', () => {
67
+ const usage = usageOf((root) => {
68
+ addNodeChild(root, shapeLikeNode('drawRectangle', 4, 0, 0, 10, 10, 'drawRectangle', 4, 20, 0, 10, 10));
69
+ addNodeChild(root, shapeLikeNode('drawRectangle', 4, 0, 0, 5, 5));
70
+ });
71
+ expect(usage.shapeCommandKeys).toEqual(['drawRectangle']);
72
+ });
73
+
74
+ it('advances by the declared argument count, so arguments are never read as command keys', () => {
75
+ // The stream is [key, argCount, ...args]. Misreading the stride would report an argument value —
76
+ // here the string 'round' — as if it were a command key. That is the failure this pins.
77
+ const usage = usageOf((root) => {
78
+ addNodeChild(root, shapeLikeNode('lineStyle', 3, 2, 0x000000, 'round', 'moveTo', 2, 0, 0));
79
+ });
80
+ expect(usage.shapeCommandKeys).toEqual(['lineStyle', 'moveTo']);
81
+ });
82
+
83
+ it('ignores a node whose data carries no command stream', () => {
84
+ expect(usageOf((root) => addNodeChild(root, createHtmlView())).shapeCommandKeys).toEqual([]);
85
+ });
86
+
87
+ it('reports a non-default blend mode and omits Normal, which needs no realization', () => {
88
+ const usage = usageOf((root) => {
89
+ const plain = createDisplayObject();
90
+ const lit = createDisplayObject();
91
+ lit.blendMode = BlendMode.Multiply;
92
+ addNodeChild(root, plain);
93
+ addNodeChild(root, lit);
94
+ });
95
+ expect(usage.blendModes).toEqual([BlendMode.Multiply]);
96
+ });
97
+
98
+ it('reports the kind of a material a node carries', () => {
99
+ const usage = usageOf((root) => {
100
+ const node = createDisplayObject();
101
+ node.material = createUnlitMaterial();
102
+ addNodeChild(root, node);
103
+ });
104
+ expect(usage.materialKinds).toEqual(['UnlitMaterial']);
105
+ });
106
+
107
+ it('leaves material kinds empty when no node carries one', () => {
108
+ expect(usageOf((root) => addNodeChild(root, createDisplayObject())).materialKinds).toEqual([]);
109
+ });
110
+
111
+ it('clears every list, so a reused record does not accumulate', () => {
112
+ const scene = createScene2D();
113
+ addNodeChild(scene.root, createHtmlView());
114
+ const usage = createScene2DKindUsage();
115
+ getScene2DKindUsage(usage, scene);
116
+ getScene2DKindUsage(usage, scene);
117
+ expect(usage.nodeKinds).toEqual([DisplayObjectKind, HtmlViewKind]);
118
+ });
119
+ });
@@ -0,0 +1,156 @@
1
+ import { getEntityRuntime } from '@flighthq/entity/contract';
2
+ import { createRectangle } from '@flighthq/geometry/contract';
3
+ import { getNodeLocalBoundsRectangle } from '@flighthq/node/contract';
4
+ import { createTexture, setTextureUvFromPixelRect } from '@flighthq/texture/contract';
5
+ import type { Image, Node, Sprite, SpriteRuntime } from '@flighthq/types/contract';
6
+ import { SpriteKind } from '@flighthq/types/contract';
7
+
8
+ import {
9
+ cloneSprite,
10
+ computeSpriteLocalBoundsRectangle,
11
+ createSprite,
12
+ createSpriteData,
13
+ createSpriteRendererData,
14
+ createSpriteRuntime,
15
+ getSpriteRuntime,
16
+ isSpriteRendererDirty,
17
+ } from './sprite';
18
+
19
+ describe('cloneSprite', () => {
20
+ it('shares the texture through a fresh sprite', () => {
21
+ const source = createSprite({ data: { texture: texture(10, 20) } });
22
+ const copy = cloneSprite(source);
23
+ expect(copy).not.toBe(source);
24
+ expect(copy.data.texture).toBe(source.data.texture);
25
+ });
26
+ });
27
+
28
+ describe('computeSpriteLocalBoundsRectangle', () => {
29
+ it('uses texture dimensions multiplied by its uv window', () => {
30
+ const imageTexture = texture(100, 200);
31
+ setTextureUvFromPixelRect(imageTexture, 10, 20, 30, 40);
32
+ const sprite = createSprite({ data: { texture: imageTexture } });
33
+ const out = createRectangle();
34
+ computeSpriteLocalBoundsRectangle(out, sprite as unknown as Node);
35
+ expect(out.width).toBe(30);
36
+ expect(out.height).toBe(40);
37
+ });
38
+
39
+ it('sets an empty size when texture is null', () => {
40
+ const sprite = createSprite();
41
+ const out = createRectangle(0, 0, 50, 60);
42
+ computeSpriteLocalBoundsRectangle(out, sprite as unknown as Node);
43
+ expect(out.width).toBe(0);
44
+ expect(out.height).toBe(0);
45
+ });
46
+ });
47
+
48
+ describe('createSprite', () => {
49
+ let sprite: Sprite;
50
+
51
+ beforeEach(() => {
52
+ sprite = createSprite();
53
+ });
54
+
55
+ it('initializes default values', () => {
56
+ expect(sprite.data.texture).toBeNull();
57
+ expect(sprite.kind).toBe(SpriteKind);
58
+ });
59
+
60
+ it('allows pre-defined values', () => {
61
+ const imageTexture = texture(10, 10);
62
+ const obj = createSprite({ data: { texture: imageTexture } });
63
+ expect(obj.data.texture).toBe(imageTexture);
64
+ });
65
+
66
+ it('returns a new object for better hidden-class performance', () => {
67
+ const base = {};
68
+ const obj = createSprite(base);
69
+ expect(obj).not.toStrictEqual(base);
70
+ });
71
+ });
72
+
73
+ describe('createSpriteData', () => {
74
+ it('returns default values', () => {
75
+ expect(createSpriteData().texture).toBeNull();
76
+ });
77
+
78
+ it('allows pre-defined values', () => {
79
+ const imageTexture = texture(10, 10);
80
+ expect(createSpriteData({ texture: imageTexture }).texture).toBe(imageTexture);
81
+ });
82
+ });
83
+
84
+ describe('createSpriteRendererData', () => {
85
+ it('creates a clean per-state stamp for the current texture', () => {
86
+ const sprite = createSprite({ data: { texture: texture(16, 16) } });
87
+ const data = createSpriteRendererData({} as never, sprite);
88
+
89
+ expect(isSpriteRendererDirty({} as never, sprite, data)).toBe(false);
90
+ });
91
+ });
92
+
93
+ describe('createSpriteRuntime', () => {
94
+ it('returns a non-null runtime', () => {
95
+ const runtime = createSpriteRuntime();
96
+ expect(runtime).not.toBeNull();
97
+ });
98
+
99
+ it('uses computeSpriteLocalBoundsRectangle', () => {
100
+ expect(createSpriteRuntime().computeLocalBoundsRectangle).toStrictEqual(computeSpriteLocalBoundsRectangle);
101
+ });
102
+
103
+ it('installs the texture-aware local-bounds validity hook', () => {
104
+ const runtime = createSpriteRuntime();
105
+ expect(typeof runtime.isLocalBoundsRectangleValid).toBe('function');
106
+ expect(runtime.localBoundsTexture).toBeNull();
107
+ expect(runtime.localBoundsTextureVersion).toBe(-1);
108
+ });
109
+ });
110
+
111
+ describe('getSpriteRuntime', () => {
112
+ it('returns the runtime of the given Sprite', () => {
113
+ expect(getSpriteRuntime(createSprite())).not.toBeNull();
114
+ });
115
+ });
116
+
117
+ describe('isSpriteRendererDirty', () => {
118
+ it('detects same-size bare texture assignment once without node invalidation', () => {
119
+ const sprite = createSprite({ data: { texture: texture(64, 64) } });
120
+ const data = createSpriteRendererData({} as never, sprite);
121
+ const runtime = getEntityRuntime(sprite) as SpriteRuntime;
122
+ const contentId = runtime.localContentId;
123
+
124
+ sprite.data.texture = texture(64, 64);
125
+
126
+ expect(isSpriteRendererDirty({} as never, sprite, data)).toBe(true);
127
+ expect(isSpriteRendererDirty({} as never, sprite, data)).toBe(false);
128
+ expect(runtime.localContentId).toBe(contentId);
129
+ });
130
+
131
+ it('detects a version bump on the same texture identity', () => {
132
+ const sprite = createSprite({ data: { texture: texture(64, 64) } });
133
+ const data = createSpriteRendererData({} as never, sprite);
134
+ sprite.data.texture!.version++;
135
+
136
+ expect(isSpriteRendererDirty({} as never, sprite, data)).toBe(true);
137
+ });
138
+ });
139
+
140
+ describe('Sprite local bounds validity', () => {
141
+ it('refreshes bounds after bare texture assignment without changing localBoundsId', () => {
142
+ const sprite = createSprite({ data: { texture: texture(16, 12) } });
143
+ expect(getNodeLocalBoundsRectangle(sprite)).toMatchObject({ width: 16, height: 12 });
144
+ const runtime = getEntityRuntime(sprite) as SpriteRuntime;
145
+ const localBoundsId = runtime.localBoundsId;
146
+
147
+ sprite.data.texture = texture(48, 30);
148
+
149
+ expect(getNodeLocalBoundsRectangle(sprite)).toMatchObject({ width: 48, height: 30 });
150
+ expect(runtime.localBoundsId).toBe(localBoundsId);
151
+ });
152
+ });
153
+
154
+ function texture(width: number, height: number) {
155
+ return createTexture({ dimension: '2d', source: { height, width } as Image });
156
+ }
package/dist/bitmap.d.ts DELETED
@@ -1,8 +0,0 @@
1
- import type { Bitmap, BitmapData, BitmapRuntime, Node, PartialNode, Rectangle } from '@flighthq/types/contract';
2
- export declare function computeBitmapLocalBoundsRectangle(out: Rectangle, source: Readonly<Node>): void;
3
- export declare function createBitmap(obj?: Readonly<PartialNode<Bitmap>>): Bitmap;
4
- export declare function createBitmapData(data?: Readonly<Partial<BitmapData>>): BitmapData;
5
- export declare function createBitmapRuntime(): BitmapRuntime;
6
- export declare function getBitmapRuntime(source: Readonly<Bitmap>): Readonly<BitmapRuntime>;
7
- export declare function setBitmapImage(source: Bitmap, value: BitmapData['image']): void;
8
- //# sourceMappingURL=bitmap.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bitmap.d.ts","sourceRoot":"","sources":["../src/bitmap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EACN,UAAU,EACV,aAAa,EAEb,IAAI,EACJ,WAAW,EACX,SAAS,EACV,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,iCAAiC,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAS9F;AAED,wBAAgB,YAAY,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAExE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,UAAU,CAMjF;AAED,wBAAgB,mBAAmB,IAAI,aAAa,CAEnD;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,aAAa,CAAC,CAElF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAM/E"}
package/dist/bitmap.js DELETED
@@ -1,41 +0,0 @@
1
- import { invalidateNodeLocalBounds, invalidateNodeLocalContent } from '@flighthq/node/contract';
2
- import { BitmapKind } from '@flighthq/types/contract';
3
- import { createNode2D, createNode2DRuntime, getNode2DRuntime } from './displayObject';
4
- export function computeBitmapLocalBoundsRectangle(out, source) {
5
- const bitmapData = source.data;
6
- if (bitmapData.sourceRectangle !== null) {
7
- out.width = bitmapData.sourceRectangle.width;
8
- out.height = bitmapData.sourceRectangle.height;
9
- }
10
- else if (bitmapData.image) {
11
- out.width = bitmapData.image.width;
12
- out.height = bitmapData.image.height;
13
- }
14
- }
15
- export function createBitmap(obj) {
16
- return createNode2D(BitmapKind, obj, createBitmapData, createBitmapRuntime);
17
- }
18
- export function createBitmapData(data) {
19
- return {
20
- image: data?.image ?? null,
21
- smoothing: data?.smoothing ?? true,
22
- sourceRectangle: data?.sourceRectangle ?? null,
23
- };
24
- }
25
- export function createBitmapRuntime() {
26
- return createNode2DRuntime(defaultMethods);
27
- }
28
- export function getBitmapRuntime(source) {
29
- return getNode2DRuntime(source);
30
- }
31
- export function setBitmapImage(source, value) {
32
- source.data.image = value;
33
- // A different image is new pixels (content) and possibly new dimensions (bounds) — not a
34
- // compositing change, so this no longer bumps appearance.
35
- invalidateNodeLocalContent(source);
36
- invalidateNodeLocalBounds(source);
37
- }
38
- const defaultMethods = {
39
- computeLocalBoundsRectangle: computeBitmapLocalBoundsRectangle,
40
- };
41
- //# sourceMappingURL=bitmap.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"bitmap.js","sourceRoot":"","sources":["../src/bitmap.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAUhG,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEtF,MAAM,UAAU,iCAAiC,CAAC,GAAc,EAAE,MAAsB;IACtF,MAAM,UAAU,GAAe,MAAM,CAAC,IAAkB,CAAC;IACzD,IAAI,UAAU,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;QACxC,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,eAAe,CAAC,KAAK,CAAC;QAC7C,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,eAAe,CAAC,MAAM,CAAC;IACjD,CAAC;SAAM,IAAI,UAAU,CAAC,KAAK,EAAE,CAAC;QAC5B,GAAG,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;QACnC,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC;IACvC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAmC;IAC9D,OAAO,YAAY,CAAC,UAAU,EAAE,GAAG,EAAE,gBAAgB,EAAE,mBAAmB,CAAW,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAoC;IACnE,OAAO;QACL,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,IAAI;QAC1B,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI;QAClC,eAAe,EAAE,IAAI,EAAE,eAAe,IAAI,IAAI;KAC/C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB;IACjC,OAAO,mBAAmB,CAAC,cAAc,CAAkB,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAwB;IACvD,OAAO,gBAAgB,CAAC,MAAM,CAAkB,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,KAA0B;IACvE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC1B,yFAAyF;IACzF,0DAA0D;IAC1D,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,cAAc,GAAsC;IACxD,2BAA2B,EAAE,iCAAiC;CAC/D,CAAC"}
@@ -1,8 +0,0 @@
1
- import type { Node, Rectangle, RenderTargetNode2D, RenderTargetNode2DData, RenderTargetNode2DOptions, RenderTargetNode2DRuntime } from '@flighthq/types/contract';
2
- export declare function computeRenderTargetNode2DLocalBoundsRectangle(out: Rectangle, source: Readonly<Node>): void;
3
- export declare function createRenderTargetNode2D(options: Readonly<RenderTargetNode2DOptions>): RenderTargetNode2D;
4
- export declare function createRenderTargetNode2DData(data?: Readonly<Partial<RenderTargetNode2DData>>): RenderTargetNode2DData;
5
- export declare function createRenderTargetNode2DRuntime(): RenderTargetNode2DRuntime;
6
- export declare function getRenderTargetNode2DRuntime(source: Readonly<RenderTargetNode2D>): Readonly<RenderTargetNode2DRuntime>;
7
- export declare function setRenderTargetNode2DSize(source: RenderTargetNode2D, width: number, height: number): void;
8
- //# sourceMappingURL=renderTargetNode2D.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderTargetNode2D.d.ts","sourceRoot":"","sources":["../src/renderTargetNode2D.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,IAAI,EACJ,SAAS,EACT,kBAAkB,EAClB,sBAAsB,EACtB,yBAAyB,EACzB,yBAAyB,EAC1B,MAAM,0BAA0B,CAAC;AAKlC,wBAAgB,6CAA6C,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAI1G;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,QAAQ,CAAC,yBAAyB,CAAC,GAAG,kBAAkB,CAOzG;AAED,wBAAgB,4BAA4B,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC,GAAG,sBAAsB,CAMrH;AAED,wBAAgB,+BAA+B,IAAI,yBAAyB,CAE3E;AAED,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,GACnC,QAAQ,CAAC,yBAAyB,CAAC,CAErC;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAKzG"}
@@ -1,35 +0,0 @@
1
- import { invalidateNodeLocalBounds } from '@flighthq/node/contract';
2
- import { RenderTargetNode2DKind } from '@flighthq/types/contract';
3
- import { createNode2D, createNode2DRuntime, getNode2DRuntime } from './displayObject';
4
- export function computeRenderTargetNode2DLocalBoundsRectangle(out, source) {
5
- const data = source.data;
6
- out.width = data.width;
7
- out.height = data.height;
8
- }
9
- export function createRenderTargetNode2D(options) {
10
- return createNode2D(RenderTargetNode2DKind, { data: options }, createRenderTargetNode2DData, createRenderTargetNode2DRuntime);
11
- }
12
- export function createRenderTargetNode2DData(data) {
13
- return {
14
- depth: data?.depth ?? false,
15
- height: data?.height ?? 0,
16
- width: data?.width ?? 0,
17
- };
18
- }
19
- export function createRenderTargetNode2DRuntime() {
20
- return createNode2DRuntime(defaultMethods);
21
- }
22
- export function getRenderTargetNode2DRuntime(source) {
23
- return getNode2DRuntime(source);
24
- }
25
- export function setRenderTargetNode2DSize(source, width, height) {
26
- if (source.data.width === width && source.data.height === height)
27
- return;
28
- source.data.width = width;
29
- source.data.height = height;
30
- invalidateNodeLocalBounds(source);
31
- }
32
- const defaultMethods = {
33
- computeLocalBoundsRectangle: computeRenderTargetNode2DLocalBoundsRectangle,
34
- };
35
- //# sourceMappingURL=renderTargetNode2D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"renderTargetNode2D.js","sourceRoot":"","sources":["../src/renderTargetNode2D.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAUpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAElE,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEtF,MAAM,UAAU,6CAA6C,CAAC,GAAc,EAAE,MAAsB;IAClG,MAAM,IAAI,GAAI,MAA6B,CAAC,IAAI,CAAC;IACjD,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACvB,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,OAA4C;IACnF,OAAO,YAAY,CACjB,sBAAsB,EACtB,EAAE,IAAI,EAAE,OAAO,EAAE,EACjB,4BAA4B,EAC5B,+BAA+B,CACV,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAAgD;IAC3F,OAAO;QACL,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK;QAC3B,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;QACzB,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;KACxB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,+BAA+B;IAC7C,OAAO,mBAAmB,CAAC,cAAc,CAA8B,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,MAAoC;IAEpC,OAAO,gBAAgB,CAAC,MAAM,CAA8B,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,MAA0B,EAAE,KAAa,EAAE,MAAc;IACjG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,KAAK,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO;IACzE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IAC1B,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IAC5B,yBAAyB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,cAAc,GAAkD;IACpE,2BAA2B,EAAE,6CAA6C;CAC3E,CAAC"}
package/dist/video.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import type { Node, PartialNode, Rectangle, Video, VideoData, VideoRuntime } from '@flighthq/types/contract';
2
- export declare function computeVideoLocalBoundsRectangle(out: Rectangle, source: Readonly<Node>): void;
3
- export declare function createVideo(obj?: Readonly<PartialNode<Video>>): Video;
4
- export declare function createVideoData(data?: Readonly<Partial<VideoData>>): VideoData;
5
- export declare function createVideoRuntime(): VideoRuntime;
6
- export declare function getVideoRuntime(source: Readonly<Video>): Readonly<VideoRuntime>;
7
- export declare function setVideoSmoothing(source: Video, value: boolean): void;
8
- export declare function setVideoSource(source: Video, value: VideoData['source']): void;
9
- //# sourceMappingURL=video.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../src/video.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAa,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAKxH,wBAAgB,gCAAgC,CAAC,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAM7F;AAED,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,QAAQ,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAErE;AAED,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,SAAS,CAK9E;AAED,wBAAgB,kBAAkB,IAAI,YAAY,CAEjD;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAE/E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAKrE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAK9E"}
package/dist/video.js DELETED
@@ -1,41 +0,0 @@
1
- import { invalidateNodeLocalBounds, invalidateNodeLocalContent } from '@flighthq/node/contract';
2
- import { VideoKind } from '@flighthq/types/contract';
3
- import { createNode2D, createNode2DRuntime, getNode2DRuntime } from './displayObject';
4
- export function computeVideoLocalBoundsRectangle(out, source) {
5
- const element = source.data.source?.element;
6
- if (element !== undefined && element !== null) {
7
- out.width = element.videoWidth;
8
- out.height = element.videoHeight;
9
- }
10
- }
11
- export function createVideo(obj) {
12
- return createNode2D(VideoKind, obj, createVideoData, createVideoRuntime);
13
- }
14
- export function createVideoData(data) {
15
- return {
16
- smoothing: data?.smoothing ?? true,
17
- source: data?.source ?? null,
18
- };
19
- }
20
- export function createVideoRuntime() {
21
- return createNode2DRuntime(defaultMethods);
22
- }
23
- export function getVideoRuntime(source) {
24
- return getNode2DRuntime(source);
25
- }
26
- export function setVideoSmoothing(source, value) {
27
- // Sampler filter mode is a content-rasterization concern, not a compositing one — same tier as a
28
- // new image on a Bitmap, and it does not change the node's bounds.
29
- source.data.smoothing = value;
30
- invalidateNodeLocalContent(source);
31
- }
32
- export function setVideoSource(source, value) {
33
- // A new source is new pixels (content) and possibly new dimensions (bounds).
34
- source.data.source = value;
35
- invalidateNodeLocalContent(source);
36
- invalidateNodeLocalBounds(source);
37
- }
38
- const defaultMethods = {
39
- computeLocalBoundsRectangle: computeVideoLocalBoundsRectangle,
40
- };
41
- //# sourceMappingURL=video.js.map
package/dist/video.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"video.js","sourceRoot":"","sources":["../src/video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAEhG,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAEtF,MAAM,UAAU,gCAAgC,CAAC,GAAc,EAAE,MAAsB;IACrF,MAAM,OAAO,GAAI,MAAM,CAAC,IAAkB,CAAC,MAAM,EAAE,OAA8C,CAAC;IAClG,IAAI,OAAO,KAAK,SAAS,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QAC9C,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC;QAC/B,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAkC;IAC5D,OAAO,YAAY,CAAC,SAAS,EAAE,GAAG,EAAE,eAAe,EAAE,kBAAkB,CAAU,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,IAAmC;IACjE,OAAO;QACL,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,IAAI;QAClC,MAAM,EAAE,IAAI,EAAE,MAAM,IAAI,IAAI;KAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB;IAChC,OAAO,mBAAmB,CAAC,cAAc,CAAiB,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAuB;IACrD,OAAO,gBAAgB,CAAC,MAAM,CAAiB,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAa,EAAE,KAAc;IAC7D,iGAAiG;IACjG,mEAAmE;IACnE,MAAM,CAAC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;IAC9B,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAa,EAAE,KAA0B;IACtE,6EAA6E;IAC7E,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IAC3B,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACnC,yBAAyB,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,cAAc,GAAqC;IACvD,2BAA2B,EAAE,gCAAgC;CAC9D,CAAC"}
@@ -1,135 +0,0 @@
1
- import { getEntityRuntime } from '@flighthq/entity/contract';
2
- import { createRectangle } from '@flighthq/geometry/contract';
3
- import {
4
- getNodeLocalBoundsRevision,
5
- getNodeLocalContentRevision,
6
- getNodeLocalTransformRevision,
7
- } from '@flighthq/node/contract';
8
- import type { Bitmap, BitmapRuntime, ImageResource, Node } from '@flighthq/types/contract';
9
- import { BitmapKind } from '@flighthq/types/contract';
10
-
11
- import {
12
- computeBitmapLocalBoundsRectangle,
13
- createBitmap,
14
- createBitmapData,
15
- createBitmapRuntime,
16
- getBitmapRuntime,
17
- setBitmapImage,
18
- } from './bitmap';
19
-
20
- describe('computeBitmapLocalBoundsRectangle', () => {
21
- it('sets out dimensions from image when image is present', () => {
22
- const bitmap = createBitmap({ data: { image: { width: 100, height: 200 } as ImageResource } });
23
- const out = createRectangle();
24
- computeBitmapLocalBoundsRectangle(out, bitmap as unknown as Node);
25
- expect(out.width).toBe(100);
26
- expect(out.height).toBe(200);
27
- });
28
-
29
- it('does not modify out when image is null', () => {
30
- const bitmap = createBitmap();
31
- const out = createRectangle(0, 0, 50, 60);
32
- computeBitmapLocalBoundsRectangle(out, bitmap as unknown as Node);
33
- expect(out.width).toBe(50);
34
- expect(out.height).toBe(60);
35
- });
36
- });
37
-
38
- describe('createBitmap', () => {
39
- let bitmap: Bitmap;
40
-
41
- beforeEach(() => {
42
- bitmap = createBitmap();
43
- });
44
-
45
- it('initializes default values', () => {
46
- expect(bitmap.data.image).toBeNull();
47
- expect(bitmap.data.smoothing).toBe(true);
48
- expect(bitmap.kind).toBe(BitmapKind);
49
- });
50
-
51
- it('allows pre-defined values', () => {
52
- const image = {} as ImageResource;
53
- const base = {
54
- data: {
55
- image: image,
56
- smoothing: false,
57
- },
58
- };
59
- const obj = createBitmap(base);
60
- expect(obj.data.image).toBe(image);
61
- expect(obj.data.smoothing).toBe(false);
62
- });
63
-
64
- it('returns a new object for better hidden-class performance', () => {
65
- const base = {};
66
- const obj = createBitmap(base);
67
- expect(obj).not.toStrictEqual(base);
68
- });
69
- });
70
-
71
- describe('createBitmapData', () => {
72
- it('returns default values', () => {
73
- const data = createBitmapData();
74
- expect(data.image).toBeNull();
75
- expect(data.smoothing).toBe(true);
76
- });
77
-
78
- it('allows pre-defined values', () => {
79
- const image = { width: 10, height: 10 } as ImageResource;
80
- const data = createBitmapData({ image, smoothing: false });
81
- expect(data.image).toBe(image);
82
- expect(data.smoothing).toBe(false);
83
- });
84
- });
85
-
86
- describe('createBitmapRuntime', () => {
87
- it('returns a non-null runtime', () => {
88
- const runtime = createBitmapRuntime();
89
- expect(runtime).not.toBeNull();
90
- });
91
-
92
- it('uses computeBitmapLocalBoundsRectangle', () => {
93
- const runtime = createBitmapRuntime();
94
- expect(runtime.computeLocalBoundsRectangle).toStrictEqual(computeBitmapLocalBoundsRectangle);
95
- });
96
- });
97
-
98
- describe('getBitmapRuntime', () => {
99
- it('returns the runtime of the given Bitmap', () => {
100
- const bitmap = createBitmap();
101
- const runtime = getBitmapRuntime(bitmap);
102
- expect(runtime).not.toBeNull();
103
- });
104
- });
105
-
106
- describe('setBitmapImage', () => {
107
- it('sets the image', () => {
108
- const bitmap = createBitmap();
109
- const image = { width: 64, height: 64 } as ImageResource;
110
- setBitmapImage(bitmap, image);
111
- expect(bitmap.data.image).toBe(image);
112
- });
113
-
114
- it('accepts null', () => {
115
- const bitmap = createBitmap({ data: { image: { width: 1, height: 1 } as ImageResource } });
116
- setBitmapImage(bitmap, null);
117
- expect(bitmap.data.image).toBeNull();
118
- });
119
-
120
- it('invalidates local bounds', () => {
121
- const bitmap = createBitmap();
122
- const runtime = getEntityRuntime(bitmap) as BitmapRuntime;
123
- const idBefore = runtime.localBoundsId;
124
- setBitmapImage(bitmap, { width: 64, height: 64 } as ImageResource);
125
- expect(runtime.localBoundsId).not.toBe(idBefore);
126
- });
127
-
128
- it('invalidates local content', () => {
129
- const bitmap = createBitmap();
130
- const runtime = getEntityRuntime(bitmap) as BitmapRuntime;
131
- const idBefore = runtime.localContentId;
132
- setBitmapImage(bitmap, { width: 64, height: 64 } as ImageResource);
133
- expect(runtime.localContentId).not.toBe(idBefore);
134
- });
135
- });
@@ -1,97 +0,0 @@
1
- import { createRectangle } from '@flighthq/geometry/contract';
2
- import type { Node, RenderTargetNode2D } from '@flighthq/types/contract';
3
- import { RenderTargetNode2DKind } from '@flighthq/types/contract';
4
-
5
- import {
6
- computeRenderTargetNode2DLocalBoundsRectangle,
7
- createRenderTargetNode2D,
8
- createRenderTargetNode2DData,
9
- createRenderTargetNode2DRuntime,
10
- getRenderTargetNode2DRuntime,
11
- setRenderTargetNode2DSize,
12
- } from './renderTargetNode2D';
13
-
14
- describe('computeRenderTargetNode2DLocalBoundsRectangle', () => {
15
- it('writes width and height from data', () => {
16
- const node = createRenderTargetNode2D({ width: 400, height: 300 });
17
- const out = createRectangle(0, 0, 0, 0);
18
-
19
- computeRenderTargetNode2DLocalBoundsRectangle(out, node as unknown as Node);
20
-
21
- expect(out.width).toBe(400);
22
- expect(out.height).toBe(300);
23
- });
24
- });
25
-
26
- describe('createRenderTargetNode2D', () => {
27
- it('creates a node with the requested dimensions and no depth by default', () => {
28
- const node = createRenderTargetNode2D({ width: 320, height: 240 });
29
-
30
- expect(node.data.depth).toBe(false);
31
- expect(node.data.height).toBe(240);
32
- expect(node.data.width).toBe(320);
33
- expect(node.kind).toBe(RenderTargetNode2DKind);
34
- });
35
-
36
- it('enables a depth attachment when requested', () => {
37
- const node = createRenderTargetNode2D({ width: 320, height: 240, depth: true });
38
-
39
- expect(node.data.depth).toBe(true);
40
- });
41
- });
42
-
43
- describe('createRenderTargetNode2DData', () => {
44
- it('returns default values', () => {
45
- const data = createRenderTargetNode2DData();
46
-
47
- expect(data.depth).toBe(false);
48
- expect(data.height).toBe(0);
49
- expect(data.width).toBe(0);
50
- });
51
-
52
- it('allows predefined values', () => {
53
- const data = createRenderTargetNode2DData({ depth: true, height: 600, width: 800 });
54
-
55
- expect(data.depth).toBe(true);
56
- expect(data.height).toBe(600);
57
- expect(data.width).toBe(800);
58
- });
59
- });
60
-
61
- describe('createRenderTargetNode2DRuntime', () => {
62
- it('returns a non-null runtime', () => {
63
- expect(createRenderTargetNode2DRuntime()).not.toBeNull();
64
- });
65
- });
66
-
67
- describe('getRenderTargetNode2DRuntime', () => {
68
- it('returns the node runtime', () => {
69
- const node = createRenderTargetNode2D({ width: 1, height: 1 });
70
-
71
- expect(getRenderTargetNode2DRuntime(node)).not.toBeNull();
72
- });
73
- });
74
-
75
- describe('setRenderTargetNode2DSize', () => {
76
- let node: RenderTargetNode2D;
77
-
78
- beforeEach(() => {
79
- node = createRenderTargetNode2D({ width: 100, height: 100 });
80
- });
81
-
82
- it('updates width and height', () => {
83
- setRenderTargetNode2DSize(node, 640, 480);
84
-
85
- expect(node.data.width).toBe(640);
86
- expect(node.data.height).toBe(480);
87
- });
88
-
89
- it('is a no-op when size is unchanged', () => {
90
- const runtime = getRenderTargetNode2DRuntime(node);
91
- const before = runtime.localBoundsId;
92
-
93
- setRenderTargetNode2DSize(node, 100, 100);
94
-
95
- expect(runtime.localBoundsId).toBe(before);
96
- });
97
- });
package/src/video.test.ts DELETED
@@ -1,117 +0,0 @@
1
- import {
2
- getNodeLocalBoundsRevision,
3
- getNodeLocalContentRevision,
4
- getNodeLocalTransformRevision,
5
- } from '@flighthq/node/contract';
6
- import type { Video } from '@flighthq/types/contract';
7
- import { VideoKind } from '@flighthq/types/contract';
8
-
9
- import {
10
- computeVideoLocalBoundsRectangle,
11
- createVideo,
12
- createVideoData,
13
- createVideoRuntime,
14
- getVideoRuntime,
15
- setVideoSmoothing,
16
- setVideoSource,
17
- } from './video';
18
-
19
- describe('computeVideoLocalBoundsRectangle', () => {
20
- it('does not modify out when source element is null', () => {
21
- const video = createVideo();
22
- const out = { x: 0, y: 0, width: 0, height: 0 };
23
- computeVideoLocalBoundsRectangle(out as never, video as never);
24
- expect(out.width).toBe(0);
25
- expect(out.height).toBe(0);
26
- });
27
-
28
- it('sets out dimensions from the video element', () => {
29
- const video = createVideo();
30
- const el = document.createElement('video');
31
- Object.defineProperty(el, 'videoWidth', { get: () => 320 });
32
- Object.defineProperty(el, 'videoHeight', { get: () => 240 });
33
- video.data.source = { element: el } as never;
34
- const out = { x: 0, y: 0, width: 0, height: 0 };
35
- computeVideoLocalBoundsRectangle(out as never, video as never);
36
- expect(out.width).toBe(320);
37
- expect(out.height).toBe(240);
38
- });
39
- });
40
-
41
- describe('createVideo', () => {
42
- let video: Video;
43
-
44
- beforeEach(() => {
45
- video = createVideo();
46
- });
47
-
48
- it('initializes default values', () => {
49
- expect(video.data.smoothing).toBe(true);
50
- expect(video.kind).toStrictEqual(VideoKind);
51
- });
52
-
53
- it('allows pre-defined values', () => {
54
- const base = {
55
- data: {
56
- smoothing: false,
57
- },
58
- };
59
- const obj = createVideo(base);
60
- expect(obj.data.smoothing).toStrictEqual(base.data.smoothing);
61
- });
62
-
63
- it('returns a new object for better hidden-class performance', () => {
64
- const base = {};
65
- const obj = createVideo(base);
66
- expect(obj).not.toStrictEqual(base);
67
- });
68
- });
69
-
70
- describe('createVideoData', () => {
71
- it('returns default values', () => {
72
- const data = createVideoData();
73
- expect(data.smoothing).toBe(true);
74
- });
75
-
76
- it('allows pre-defined values', () => {
77
- const data = createVideoData({ smoothing: false });
78
- expect(data.smoothing).toBe(false);
79
- });
80
- });
81
-
82
- describe('createVideoRuntime', () => {
83
- it('returns a non-null runtime', () => {
84
- const runtime = createVideoRuntime();
85
- expect(runtime).not.toBeNull();
86
- });
87
- });
88
-
89
- describe('getVideoRuntime', () => {
90
- it('returns the runtime for a Video', () => {
91
- const video = createVideo();
92
- const runtime = getVideoRuntime(video);
93
- expect(runtime).not.toBeNull();
94
- });
95
- });
96
-
97
- describe('setVideoSmoothing', () => {
98
- it('updates the smoothing field', () => {
99
- const video = createVideo();
100
- setVideoSmoothing(video, false);
101
- expect(video.data.smoothing).toBe(false);
102
- setVideoSmoothing(video, true);
103
- expect(video.data.smoothing).toBe(true);
104
- });
105
- });
106
-
107
- describe('setVideoSource', () => {
108
- it('updates the source field', () => {
109
- const video = createVideo();
110
- const el = document.createElement('video');
111
- const source = { element: el } as never;
112
- setVideoSource(video, source);
113
- expect(video.data.source).toBe(source);
114
- setVideoSource(video, null);
115
- expect(video.data.source).toBeNull();
116
- });
117
- });