@flighthq/render 0.5.1-next.1629.669e7c5 → 0.5.1-next.1680.bdc44c6

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/README.md CHANGED
@@ -13,5 +13,5 @@ Import the supported application-facing API from `@flighthq/render`. The `@fligh
13
13
  This package is part of the locked-version Flight SDK graph. Applications may instead install and import `@flighthq/sdk` when package-level tree shaking is sufficient.
14
14
 
15
15
  - [Flight project](https://github.com/flighthq/flight)
16
- - [Source for @flighthq/render@0.5.1-next.1629.669e7c5](https://github.com/flighthq/flight/tree/669e7c57b5177f4dba43dd9e861db543c4d72d2d/packages/render)
17
- - [License](https://github.com/flighthq/flight/blob/669e7c57b5177f4dba43dd9e861db543c4d72d2d/LICENSE.md)
16
+ - [Source for @flighthq/render@0.5.1-next.1680.bdc44c6](https://github.com/flighthq/flight/tree/bdc44c63675b7c50301154e66b79e2d29d6262da/packages/render)
17
+ - [License](https://github.com/flighthq/flight/blob/bdc44c63675b7c50301154e66b79e2d29d6262da/LICENSE.md)
@@ -1,3 +1,4 @@
1
+ export * from './mergeRenderOptions';
1
2
  export * from './enableColorAdjustmentGuards';
2
3
  export * from './enableColorAdjustments';
3
4
  export * from './enableSceneRenderGuards';
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,eAAe,CAAC"}
package/dist/contract.js CHANGED
@@ -1,3 +1,4 @@
1
+ export * from './mergeRenderOptions';
1
2
  export * from './enableColorAdjustmentGuards';
2
3
  export * from './enableColorAdjustments';
3
4
  export * from './enableSceneRenderGuards';
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAC;AACrC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,0BAA0B,CAAC;AACzC,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,YAAY,CAAC;AAC3B,cAAc,4BAA4B,CAAC;AAC3C,cAAc,eAAe,CAAC"}
@@ -1,4 +1,5 @@
1
- import type { ImageSurface, ImageSurfaceCreator } from '@flighthq/types/contract';
2
- export declare function createImageSurface(provider: Readonly<ImageSurfaceCreator>, width: number, height: number): ImageSurface | null;
3
- export declare function destroyImageSurface(surface: ImageSurface): void;
1
+ import type { CanvasSurface, HostCanvasCapability } from '@flighthq/types/contract';
2
+ export declare function createCanvasHostSurface(host: Readonly<HostCanvasCapability>, width: number, height: number): CanvasSurface | null;
3
+ export declare function destroyCanvasHostSurface(surface: CanvasSurface): void;
4
+ export declare function getCanvasHostSurface(surface: CanvasSurface): Readonly<HostCanvasCapability> | null;
4
5
  //# sourceMappingURL=imageSurface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imageSurface.d.ts","sourceRoot":"","sources":["../src/imageSurface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAElF,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,QAAQ,CAAC,mBAAmB,CAAC,EACvC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,YAAY,GAAG,IAAI,CAIrB;AAKD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAK/D"}
1
+ {"version":3,"file":"imageSurface.d.ts","sourceRoot":"","sources":["../src/imageSurface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEpF,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,QAAQ,CAAC,oBAAoB,CAAC,EACpC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,aAAa,GAAG,IAAI,CAItB;AAKD,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,aAAa,GAAG,IAAI,CAKrE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,aAAa,GAAG,QAAQ,CAAC,oBAAoB,CAAC,GAAG,IAAI,CAElG"}
@@ -1,18 +1,21 @@
1
- export function createImageSurface(provider, width, height) {
2
- const surface = provider.createImageSurface(width, height);
1
+ export function createCanvasHostSurface(host, width, height) {
2
+ const surface = host.createSurface(width, height);
3
3
  if (surface !== null)
4
- _surfaceProviders.set(surface, provider);
4
+ _surfaceHosts.set(surface, host);
5
5
  return surface;
6
6
  }
7
- // A surface must return to the provider that allocated it even when the provider reference changes
8
- // during its lifetime. Delete the ownership record before invoking the provider so repeated or
9
- // reentrant destruction is a no-op and no non-GC resource can be freed twice.
10
- export function destroyImageSurface(surface) {
11
- const provider = _surfaceProviders.get(surface);
12
- if (provider === undefined)
7
+ // A surface must return to the host that allocated it even when the host reference changes during its
8
+ // lifetime. Delete the ownership record before invoking the host so repeated or reentrant destruction is
9
+ // a no-op and no non-GC resource can be freed twice.
10
+ export function destroyCanvasHostSurface(surface) {
11
+ const host = _surfaceHosts.get(surface);
12
+ if (host === undefined)
13
13
  return;
14
- _surfaceProviders.delete(surface);
15
- provider.destroyImageSurface(surface);
14
+ _surfaceHosts.delete(surface);
15
+ host.destroySurface(surface);
16
16
  }
17
- const _surfaceProviders = new WeakMap();
17
+ export function getCanvasHostSurface(surface) {
18
+ return _surfaceHosts.get(surface) ?? null;
19
+ }
20
+ const _surfaceHosts = new WeakMap();
18
21
  //# sourceMappingURL=imageSurface.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"imageSurface.js","sourceRoot":"","sources":["../src/imageSurface.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,kBAAkB,CAChC,QAAuC,EACvC,KAAa,EACb,MAAc;IAEd,MAAM,OAAO,GAAG,QAAQ,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3D,IAAI,OAAO,KAAK,IAAI;QAAE,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC/D,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,mGAAmG;AACnG,+FAA+F;AAC/F,8EAA8E;AAC9E,MAAM,UAAU,mBAAmB,CAAC,OAAqB;IACvD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO;IACnC,iBAAiB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClC,QAAQ,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,iBAAiB,GAAG,IAAI,OAAO,EAA+C,CAAC"}
1
+ {"version":3,"file":"imageSurface.js","sourceRoot":"","sources":["../src/imageSurface.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,uBAAuB,CACrC,IAAoC,EACpC,KAAa,EACb,MAAc;IAEd,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAClD,IAAI,OAAO,KAAK,IAAI;QAAE,aAAa,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,sGAAsG;AACtG,yGAAyG;AACzG,qDAAqD;AACrD,MAAM,UAAU,wBAAwB,CAAC,OAAsB;IAC7D,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO;IAC/B,aAAa,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAsB;IACzD,OAAO,aAAa,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC;AAC5C,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,OAAO,EAAiD,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export { mergeRenderOptions } from './mergeRenderOptions';
1
2
  export * from './enableColorAdjustments';
2
3
  export * from './enableSceneRenderGuards';
3
4
  export * from './explainScene2DPipelineCoverage';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACrG,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACrG,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ export { mergeRenderOptions } from './mergeRenderOptions';
1
2
  export * from './enableColorAdjustments';
2
3
  export * from './enableSceneRenderGuards';
3
4
  export * from './explainScene2DPipelineCoverage';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACrG,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gBAAgB,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,+BAA+B,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACnG,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAE,4BAA4B,EAAE,6BAA6B,EAAE,MAAM,wBAAwB,CAAC;AACrG,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACzE,cAAc,4BAA4B,CAAC;AAC3C,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { RenderStateOptions } from '@flighthq/types/contract';
2
+ /**
3
+ * Composes render-state option fragments into one, field by field.
4
+ *
5
+ * Every field of `RenderStateOptions` is named explicitly rather than folded by a generic deep merge.
6
+ * That is the point: a generic merge has to GUESS how an unfamiliar field composes, and it guesses
7
+ * silently. Naming each field means adding one to `RenderStateOptions` without deciding how it merges
8
+ * shows up as a compile error here and a failing exhaustiveness test, instead of as a field that
9
+ * quietly takes the last fragment's value in someone's build.
10
+ *
11
+ * The three shapes compose differently, and the difference is load-bearing:
12
+ *
13
+ * - **Kind-keyed maps merge**, later fragments winning per key. Two content files naming different
14
+ * kinds must both survive; two naming the same kind agree.
15
+ * - **Nullable policy functions are last-wins scalars.** A tessellator or a guard is one choice, not a
16
+ * collection, so the most recently stated fragment is the one the caller asked for.
17
+ * - **`undefined` never overwrites.** A fragment that does not mention a field is silent about it, which
18
+ * is different from a fragment that sets it to null.
19
+ *
20
+ * Deterministic and non-mutating: no input map is aliased into the result, and the result depends only
21
+ * on argument order.
22
+ */
23
+ export declare function mergeRenderOptions(...options: readonly Readonly<RenderStateOptions>[]): RenderStateOptions;
24
+ //# sourceMappingURL=mergeRenderOptions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRenderOptions.d.ts","sourceRoot":"","sources":["../src/mergeRenderOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,OAAO,EAAE,SAAS,QAAQ,CAAC,kBAAkB,CAAC,EAAE,GAAG,kBAAkB,CAuB1G"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Composes render-state option fragments into one, field by field.
3
+ *
4
+ * Every field of `RenderStateOptions` is named explicitly rather than folded by a generic deep merge.
5
+ * That is the point: a generic merge has to GUESS how an unfamiliar field composes, and it guesses
6
+ * silently. Naming each field means adding one to `RenderStateOptions` without deciding how it merges
7
+ * shows up as a compile error here and a failing exhaustiveness test, instead of as a field that
8
+ * quietly takes the last fragment's value in someone's build.
9
+ *
10
+ * The three shapes compose differently, and the difference is load-bearing:
11
+ *
12
+ * - **Kind-keyed maps merge**, later fragments winning per key. Two content files naming different
13
+ * kinds must both survive; two naming the same kind agree.
14
+ * - **Nullable policy functions are last-wins scalars.** A tessellator or a guard is one choice, not a
15
+ * collection, so the most recently stated fragment is the one the caller asked for.
16
+ * - **`undefined` never overwrites.** A fragment that does not mention a field is silent about it, which
17
+ * is different from a fragment that sets it to null.
18
+ *
19
+ * Deterministic and non-mutating: no input map is aliased into the result, and the result depends only
20
+ * on argument order.
21
+ */
22
+ export function mergeRenderOptions(...options) {
23
+ const merged = {};
24
+ for (const fragment of options) {
25
+ if (fragment.canvasShapeCommands !== undefined) {
26
+ merged.canvasShapeCommands = new Map([...(merged.canvasShapeCommands ?? []), ...fragment.canvasShapeCommands]);
27
+ }
28
+ if (fragment.colorAdjustments !== undefined)
29
+ merged.colorAdjustments = fragment.colorAdjustments;
30
+ if (fragment.colorAdjustmentUnsupportedGuard !== undefined) {
31
+ merged.colorAdjustmentUnsupportedGuard = fragment.colorAdjustmentUnsupportedGuard;
32
+ }
33
+ if (fragment.effectPaddingResolvers !== undefined) {
34
+ merged.effectPaddingResolvers = new Map([
35
+ ...(merged.effectPaddingResolvers ?? []),
36
+ ...fragment.effectPaddingResolvers,
37
+ ]);
38
+ }
39
+ if (fragment.nodeRenderers !== undefined) {
40
+ merged.nodeRenderers = new Map([...(merged.nodeRenderers ?? []), ...fragment.nodeRenderers]);
41
+ }
42
+ if (fragment.renderRootGuard !== undefined)
43
+ merged.renderRootGuard = fragment.renderRootGuard;
44
+ if (fragment.strokeTessellator !== undefined)
45
+ merged.strokeTessellator = fragment.strokeTessellator;
46
+ }
47
+ return merged;
48
+ }
49
+ //# sourceMappingURL=mergeRenderOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mergeRenderOptions.js","sourceRoot":"","sources":["../src/mergeRenderOptions.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAG,OAAgD;IACpF,MAAM,MAAM,GAAuB,EAAE,CAAC;IACtC,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAC/B,IAAI,QAAQ,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;YAC/C,MAAM,CAAC,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC;QACjH,CAAC;QACD,IAAI,QAAQ,CAAC,gBAAgB,KAAK,SAAS;YAAE,MAAM,CAAC,gBAAgB,GAAG,QAAQ,CAAC,gBAAgB,CAAC;QACjG,IAAI,QAAQ,CAAC,+BAA+B,KAAK,SAAS,EAAE,CAAC;YAC3D,MAAM,CAAC,+BAA+B,GAAG,QAAQ,CAAC,+BAA+B,CAAC;QACpF,CAAC;QACD,IAAI,QAAQ,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;YAClD,MAAM,CAAC,sBAAsB,GAAG,IAAI,GAAG,CAAC;gBACtC,GAAG,CAAC,MAAM,CAAC,sBAAsB,IAAI,EAAE,CAAC;gBACxC,GAAG,QAAQ,CAAC,sBAAsB;aACnC,CAAC,CAAC;QACL,CAAC;QACD,IAAI,QAAQ,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;YACzC,MAAM,CAAC,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,IAAI,EAAE,CAAC,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC;QAC/F,CAAC;QACD,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;YAAE,MAAM,CAAC,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;QAC9F,IAAI,QAAQ,CAAC,iBAAiB,KAAK,SAAS;YAAE,MAAM,CAAC,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAC;IACtG,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"renderState.d.ts","sourceRoot":"","sources":["../src/renderState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,+BAA+B,EAC/B,WAAW,EACX,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAIzE;AAOD,wBAAgB,wBAAwB,IAAI,kBAAkB,CAkB7D;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAO3D;AAED,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,WAAW,GAAG,+BAA+B,GAAG,IAAI,CAE7G;AAID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAW9G"}
1
+ {"version":3,"file":"renderState.d.ts","sourceRoot":"","sources":["../src/renderState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,+BAA+B,EAC/B,WAAW,EACX,kBAAkB,EAElB,kBAAkB,EACnB,MAAM,0BAA0B,CAAC;AAGlC,wBAAgB,iBAAiB,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAIzE;AAOD,wBAAgB,wBAAwB,IAAI,kBAAkB,CAkB7D;AAID,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAO3D;AAED,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,WAAW,GAAG,+BAA+B,GAAG,IAAI,CAE7G;AAID,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,kBAAkB,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,kBAAkB,CAAC,WAAW,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAY9G"}
@@ -53,7 +53,8 @@ export function initializeRenderState(state, obj) {
53
53
  state.currentClipDepth = obj?.currentClipDepth ?? 0;
54
54
  state.displayObjectClipHooks = obj?.displayObjectClipHooks ?? null;
55
55
  state.pixelRatio = obj?.pixelRatio ?? 1;
56
- state.imageSurfaceProvider = obj?.imageSurfaceProvider ?? null;
56
+ state.canvasHost = obj?.canvasHost ?? null;
57
+ state.imageHost = obj?.imageHost ?? null;
57
58
  state.renderAlpha = obj?.renderAlpha ?? 1;
58
59
  state.renderBlendMode = obj?.renderBlendMode ?? BlendMode.Normal;
59
60
  state.roundPixels = obj?.roundPixels ?? false;
@@ -1 +1 @@
1
- {"version":3,"file":"renderState.js","sourceRoot":"","sources":["../src/renderState.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"renderState.js","sourceRoot":"","sources":["../src/renderState.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flighthq/render",
3
- "version": "0.5.1-next.1629.669e7c5",
3
+ "version": "0.5.1-next.1680.bdc44c6",
4
4
  "author": "Joshua Granick and other contributors",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,18 +38,18 @@
38
38
  "clean:dist": "tsx ../../scripts/clean-package-dist.ts"
39
39
  },
40
40
  "dependencies": {
41
- "@flighthq/adjustments": "0.5.1-next.1629.669e7c5",
42
- "@flighthq/camera": "0.5.1-next.1629.669e7c5",
43
- "@flighthq/color": "0.5.1-next.1629.669e7c5",
44
- "@flighthq/entity": "0.5.1-next.1629.669e7c5",
45
- "@flighthq/geometry": "0.5.1-next.1629.669e7c5",
46
- "@flighthq/log": "0.5.1-next.1629.669e7c5",
47
- "@flighthq/materials": "0.5.1-next.1629.669e7c5",
48
- "@flighthq/mesh": "0.5.1-next.1629.669e7c5",
49
- "@flighthq/node": "0.5.1-next.1629.669e7c5",
50
- "@flighthq/registry": "0.5.1-next.1629.669e7c5",
51
- "@flighthq/signals": "0.5.1-next.1629.669e7c5",
52
- "@flighthq/types": "0.5.1-next.1629.669e7c5"
41
+ "@flighthq/adjustments": "0.5.1-next.1680.bdc44c6",
42
+ "@flighthq/camera": "0.5.1-next.1680.bdc44c6",
43
+ "@flighthq/color": "0.5.1-next.1680.bdc44c6",
44
+ "@flighthq/entity": "0.5.1-next.1680.bdc44c6",
45
+ "@flighthq/geometry": "0.5.1-next.1680.bdc44c6",
46
+ "@flighthq/log": "0.5.1-next.1680.bdc44c6",
47
+ "@flighthq/materials": "0.5.1-next.1680.bdc44c6",
48
+ "@flighthq/mesh": "0.5.1-next.1680.bdc44c6",
49
+ "@flighthq/node": "0.5.1-next.1680.bdc44c6",
50
+ "@flighthq/registry": "0.5.1-next.1680.bdc44c6",
51
+ "@flighthq/signals": "0.5.1-next.1680.bdc44c6",
52
+ "@flighthq/types": "0.5.1-next.1680.bdc44c6"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@flighthq/scene2d": "*",
@@ -1,74 +1,89 @@
1
- import { allocateEntity, finishEntity } from '@flighthq/entity/contract';
2
- import type { Entity, ImageSurface, ImageSurfaceCreator } from '@flighthq/types/contract';
1
+ import type { CanvasSurface, HostCanvasCapability } from '@flighthq/types/contract';
3
2
 
4
- import { createImageSurface, destroyImageSurface } from './imageSurface';
3
+ import { createCanvasHostSurface, destroyCanvasHostSurface, getCanvasHostSurface } from './imageSurface';
5
4
 
6
- function entityProvider(fields: Omit<ImageSurfaceCreator, keyof Entity>): ImageSurfaceCreator {
7
- return (() => {
8
- const out = allocateEntity<any>();
9
- Object.assign(out, fields);
10
- return finishEntity(out);
11
- })();
5
+ function mockHost(overrides: Partial<HostCanvasCapability> = {}): HostCanvasCapability {
6
+ return {
7
+ acquire: () => null,
8
+ create: () => null,
9
+ createImageResource: () => ({}) as any,
10
+ createSurface: overrides.createSurface ?? (() => null),
11
+ destroySurface: overrides.destroySurface ?? (() => {}),
12
+ release: () => {},
13
+ ...overrides,
14
+ } as HostCanvasCapability;
12
15
  }
13
16
 
14
- describe('createImageSurface', () => {
15
- it('passes exact dimensions through the given provider and preserves its result', () => {
16
- const surface = {} as ImageSurface;
17
- const create = vi.fn(() => surface);
18
- const provider = entityProvider({ createImageSurface: create, destroyImageSurface() {} });
17
+ describe('createCanvasHostSurface', () => {
18
+ it('passes exact dimensions through the given host and preserves its result', () => {
19
+ const surface = {} as CanvasSurface;
20
+ const createSurface = vi.fn(() => surface);
21
+ const host = mockHost({ createSurface });
19
22
 
20
- expect(createImageSurface(provider, 30, 40)).toBe(surface);
21
- expect(create).toHaveBeenCalledOnce();
22
- expect(create).toHaveBeenCalledWith(30, 40);
23
+ expect(createCanvasHostSurface(host, 30, 40)).toBe(surface);
24
+ expect(createSurface).toHaveBeenCalledOnce();
25
+ expect(createSurface).toHaveBeenCalledWith(30, 40);
23
26
  });
24
27
 
25
- it('preserves provider refusal as expected absence', () => {
26
- const provider = entityProvider({ createImageSurface: () => null, destroyImageSurface() {} });
27
- expect(createImageSurface(provider, 10, 20)).toBeNull();
28
+ it('preserves host refusal as expected absence', () => {
29
+ const host = mockHost({ createSurface: () => null });
30
+ expect(createCanvasHostSurface(host, 10, 20)).toBeNull();
28
31
  });
29
32
  });
30
33
 
31
- describe('destroyImageSurface', () => {
32
- it('routes each surface to its creator even when different providers were used', () => {
33
- const firstSurface = {} as ImageSurface;
34
- const secondSurface = {} as ImageSurface;
34
+ describe('destroyCanvasHostSurface', () => {
35
+ it('routes each surface to its host even when different hosts were used', () => {
36
+ const firstSurface = {} as CanvasSurface;
37
+ const secondSurface = {} as CanvasSurface;
35
38
  const firstDestroy = vi.fn();
36
39
  const secondDestroy = vi.fn();
37
- const first = entityProvider({
38
- createImageSurface: () => firstSurface,
39
- destroyImageSurface: firstDestroy,
40
- });
41
- const second = entityProvider({
42
- createImageSurface: () => secondSurface,
43
- destroyImageSurface: secondDestroy,
44
- });
40
+ const first = mockHost({ createSurface: () => firstSurface, destroySurface: firstDestroy });
41
+ const second = mockHost({ createSurface: () => secondSurface, destroySurface: secondDestroy });
45
42
 
46
- expect(createImageSurface(first, 10, 20)).toBe(firstSurface);
47
- expect(createImageSurface(second, 30, 40)).toBe(secondSurface);
43
+ expect(createCanvasHostSurface(first, 10, 20)).toBe(firstSurface);
44
+ expect(createCanvasHostSurface(second, 30, 40)).toBe(secondSurface);
48
45
 
49
- destroyImageSurface(firstSurface);
50
- destroyImageSurface(secondSurface);
46
+ destroyCanvasHostSurface(firstSurface);
47
+ destroyCanvasHostSurface(secondSurface);
51
48
 
52
49
  expect(firstDestroy).toHaveBeenCalledExactlyOnceWith(firstSurface);
53
50
  expect(secondDestroy).toHaveBeenCalledExactlyOnceWith(secondSurface);
54
51
  });
55
52
 
56
53
  it('is a no-op after the surface has been destroyed once', () => {
57
- const surface = {} as ImageSurface;
58
- const destroy = vi.fn();
59
- const provider = entityProvider({
60
- createImageSurface: () => surface,
61
- destroyImageSurface: destroy,
62
- });
63
- expect(createImageSurface(provider, 10, 20)).toBe(surface);
64
-
65
- destroyImageSurface(surface);
66
- destroyImageSurface(surface);
67
-
68
- expect(destroy).toHaveBeenCalledOnce();
54
+ const surface = {} as CanvasSurface;
55
+ const destroySurface = vi.fn();
56
+ const host = mockHost({ createSurface: () => surface, destroySurface });
57
+ expect(createCanvasHostSurface(host, 10, 20)).toBe(surface);
58
+
59
+ destroyCanvasHostSurface(surface);
60
+ destroyCanvasHostSurface(surface);
61
+
62
+ expect(destroySurface).toHaveBeenCalledOnce();
69
63
  });
70
64
 
71
65
  it('is a no-op for an unknown surface', () => {
72
- expect(() => destroyImageSurface({} as ImageSurface)).not.toThrow();
66
+ expect(() => destroyCanvasHostSurface({} as CanvasSurface)).not.toThrow();
67
+ });
68
+ });
69
+
70
+ describe('getCanvasHostSurface', () => {
71
+ it('returns the host that created the surface', () => {
72
+ const surface = {} as CanvasSurface;
73
+ const host = mockHost({ createSurface: () => surface });
74
+ createCanvasHostSurface(host, 1, 1);
75
+ expect(getCanvasHostSurface(surface)).toBe(host);
76
+ });
77
+
78
+ it('returns null for an unknown surface', () => {
79
+ expect(getCanvasHostSurface({} as CanvasSurface)).toBeNull();
80
+ });
81
+
82
+ it('returns null after the surface has been destroyed', () => {
83
+ const surface = {} as CanvasSurface;
84
+ const host = mockHost({ createSurface: () => surface });
85
+ createCanvasHostSurface(host, 1, 1);
86
+ destroyCanvasHostSurface(surface);
87
+ expect(getCanvasHostSurface(surface)).toBeNull();
73
88
  });
74
89
  });
@@ -0,0 +1,79 @@
1
+ import type { RenderStateOptions } from '@flighthq/types/contract';
2
+
3
+ import { mergeRenderOptions } from './mergeRenderOptions';
4
+
5
+ // Every field of RenderStateOptions, listed once. The exhaustiveness test below compares this against
6
+ // what the type actually declares, so ADDING A FIELD TO RenderStateOptions FAILS HERE until someone
7
+ // decides how it composes. That is the drift alarm: a silently unmerged field is the failure mode a
8
+ // generic deep merge would have hidden.
9
+ const MAP_FIELDS = ['canvasShapeCommands', 'effectPaddingResolvers', 'nodeRenderers'] as const;
10
+ const LAST_WINS_FIELDS = [
11
+ 'colorAdjustments',
12
+ 'colorAdjustmentUnsupportedGuard',
13
+ 'renderRootGuard',
14
+ 'strokeTessellator',
15
+ ] as const;
16
+
17
+ describe('mergeRenderOptions', () => {
18
+ it('covers every field RenderStateOptions declares', () => {
19
+ const probe: Required<RenderStateOptions> = {
20
+ canvasShapeCommands: new Map(),
21
+ colorAdjustments: null,
22
+ colorAdjustmentUnsupportedGuard: null,
23
+ effectPaddingResolvers: new Map(),
24
+ nodeRenderers: new Map(),
25
+ renderRootGuard: null,
26
+ strokeTessellator: null,
27
+ };
28
+ expect(Object.keys(probe).sort()).toEqual([...MAP_FIELDS, ...LAST_WINS_FIELDS].sort());
29
+ });
30
+
31
+ it.each(MAP_FIELDS)('merges %s so entries from both fragments survive', (field) => {
32
+ const merged = mergeRenderOptions(
33
+ { [field]: new Map([['A', 'first']]) } as never,
34
+ { [field]: new Map([['B', 'second']]) } as never,
35
+ );
36
+ expect([...(merged[field] as unknown as Map<string, string>).entries()]).toEqual([
37
+ ['A', 'first'],
38
+ ['B', 'second'],
39
+ ]);
40
+ });
41
+
42
+ it.each(MAP_FIELDS)('lets a later fragment win per key in %s', (field) => {
43
+ const merged = mergeRenderOptions(
44
+ { [field]: new Map([['A', 'first']]) } as never,
45
+ { [field]: new Map([['A', 'second']]) } as never,
46
+ );
47
+ expect((merged[field] as unknown as Map<string, string>).get('A')).toBe('second');
48
+ });
49
+
50
+ it.each(MAP_FIELDS)('does not alias an input map into the result for %s', (field) => {
51
+ const input = new Map([['A', 'first']]);
52
+ const merged = mergeRenderOptions({ [field]: input } as never);
53
+ (merged[field] as unknown as Map<string, string>).set('B', 'added');
54
+ expect([...input.keys()]).toEqual(['A']);
55
+ });
56
+
57
+ it.each(LAST_WINS_FIELDS)('takes the last stated value for %s', (field) => {
58
+ const first = (() => null) as never;
59
+ const second = (() => null) as never;
60
+ expect(mergeRenderOptions({ [field]: first } as never, { [field]: second } as never)[field]).toBe(second);
61
+ });
62
+
63
+ it.each([...MAP_FIELDS, ...LAST_WINS_FIELDS])('leaves %s untouched when a later fragment omits it', (field) => {
64
+ const stated = mergeRenderOptions({ [field]: new Map([['A', 'v']]) } as never, {});
65
+ expect(stated[field]).toBeDefined();
66
+ });
67
+
68
+ it('distinguishes an omitted field from one explicitly set to null', () => {
69
+ const tessellator = (() => null) as never;
70
+ expect(mergeRenderOptions({ strokeTessellator: tessellator }, {}).strokeTessellator).toBe(tessellator);
71
+ expect(mergeRenderOptions({ strokeTessellator: tessellator }, { strokeTessellator: null }).strokeTessellator).toBe(
72
+ null,
73
+ );
74
+ });
75
+
76
+ it('returns an empty object for no fragments', () => {
77
+ expect(mergeRenderOptions()).toEqual({});
78
+ });
79
+ });