@codexo/exojs-tilemap 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +33 -26
  2. package/dist/esm/ChunkSource.d.ts +33 -0
  3. package/dist/esm/ChunkSource.d.ts.map +1 -0
  4. package/dist/esm/ChunkStreamer.d.ts +98 -0
  5. package/dist/esm/ChunkStreamer.d.ts.map +1 -0
  6. package/dist/esm/ChunkStreamer.js +201 -0
  7. package/dist/esm/ChunkStreamer.js.map +1 -0
  8. package/dist/esm/ImageLayer.d.ts +11 -3
  9. package/dist/esm/ImageLayer.d.ts.map +1 -0
  10. package/dist/esm/ImageLayer.js +71 -64
  11. package/dist/esm/ImageLayer.js.map +1 -1
  12. package/dist/esm/ImageLayerNode.d.ts +89 -0
  13. package/dist/esm/ImageLayerNode.d.ts.map +1 -0
  14. package/dist/esm/ImageLayerNode.js +205 -0
  15. package/dist/esm/ImageLayerNode.js.map +1 -0
  16. package/dist/esm/MapObject.d.ts +70 -0
  17. package/dist/esm/MapObject.d.ts.map +1 -0
  18. package/dist/esm/MapObject.js +34 -0
  19. package/dist/esm/MapObject.js.map +1 -0
  20. package/dist/esm/MapObjectSpawner.d.ts +133 -0
  21. package/dist/esm/MapObjectSpawner.d.ts.map +1 -0
  22. package/dist/esm/MapObjectSpawner.js +147 -0
  23. package/dist/esm/MapObjectSpawner.js.map +1 -0
  24. package/dist/esm/MapSpawnSession.d.ts +53 -0
  25. package/dist/esm/MapSpawnSession.d.ts.map +1 -0
  26. package/dist/esm/MapSpawnSession.js +88 -0
  27. package/dist/esm/MapSpawnSession.js.map +1 -0
  28. package/dist/esm/MapWorld.d.ts +134 -0
  29. package/dist/esm/MapWorld.d.ts.map +1 -0
  30. package/dist/esm/MapWorld.js +150 -0
  31. package/dist/esm/MapWorld.js.map +1 -0
  32. package/dist/esm/MapWorldRuntime.d.ts +182 -0
  33. package/dist/esm/MapWorldRuntime.d.ts.map +1 -0
  34. package/dist/esm/MapWorldRuntime.js +261 -0
  35. package/dist/esm/MapWorldRuntime.js.map +1 -0
  36. package/dist/esm/ObjectLayer.d.ts +93 -7
  37. package/dist/esm/ObjectLayer.d.ts.map +1 -0
  38. package/dist/esm/ObjectLayer.js +184 -167
  39. package/dist/esm/ObjectLayer.js.map +1 -1
  40. package/dist/esm/SampledChunkSource.d.ts +43 -0
  41. package/dist/esm/SampledChunkSource.d.ts.map +1 -0
  42. package/dist/esm/SampledChunkSource.js +48 -0
  43. package/dist/esm/SampledChunkSource.js.map +1 -0
  44. package/dist/esm/TileAnimator.d.ts +12 -2
  45. package/dist/esm/TileAnimator.d.ts.map +1 -0
  46. package/dist/esm/TileAnimator.js +154 -165
  47. package/dist/esm/TileAnimator.js.map +1 -1
  48. package/dist/esm/TileChunk.d.ts +30 -5
  49. package/dist/esm/TileChunk.d.ts.map +1 -0
  50. package/dist/esm/TileChunk.js +190 -188
  51. package/dist/esm/TileChunk.js.map +1 -1
  52. package/dist/esm/TileChunkNode.d.ts +18 -3
  53. package/dist/esm/TileChunkNode.d.ts.map +1 -0
  54. package/dist/esm/TileChunkNode.js +104 -85
  55. package/dist/esm/TileChunkNode.js.map +1 -1
  56. package/dist/esm/TileLayer.d.ts +104 -24
  57. package/dist/esm/TileLayer.d.ts.map +1 -0
  58. package/dist/esm/TileLayer.js +511 -469
  59. package/dist/esm/TileLayer.js.map +1 -1
  60. package/dist/esm/TileLayerNode.d.ts +52 -11
  61. package/dist/esm/TileLayerNode.d.ts.map +1 -0
  62. package/dist/esm/TileLayerNode.js +224 -166
  63. package/dist/esm/TileLayerNode.js.map +1 -1
  64. package/dist/esm/TileMap.d.ts +96 -31
  65. package/dist/esm/TileMap.d.ts.map +1 -0
  66. package/dist/esm/TileMap.js +401 -357
  67. package/dist/esm/TileMap.js.map +1 -1
  68. package/dist/esm/TileMapBand.d.ts +42 -29
  69. package/dist/esm/TileMapBand.d.ts.map +1 -0
  70. package/dist/esm/TileMapBand.js +151 -158
  71. package/dist/esm/TileMapBand.js.map +1 -1
  72. package/dist/esm/TileMapNode.d.ts +34 -18
  73. package/dist/esm/TileMapNode.d.ts.map +1 -0
  74. package/dist/esm/TileMapNode.js +122 -109
  75. package/dist/esm/TileMapNode.js.map +1 -1
  76. package/dist/esm/TileMapView.d.ts +108 -47
  77. package/dist/esm/TileMapView.d.ts.map +1 -0
  78. package/dist/esm/TileMapView.js +385 -338
  79. package/dist/esm/TileMapView.js.map +1 -1
  80. package/dist/esm/TileSet.d.ts +15 -6
  81. package/dist/esm/TileSet.d.ts.map +1 -0
  82. package/dist/esm/TileSet.js +161 -181
  83. package/dist/esm/TileSet.js.map +1 -1
  84. package/dist/esm/WangSet.d.ts +5 -4
  85. package/dist/esm/WangSet.d.ts.map +1 -0
  86. package/dist/esm/WangSet.js +70 -78
  87. package/dist/esm/WangSet.js.map +1 -1
  88. package/dist/esm/WorkerSampledChunkSource.d.ts +95 -0
  89. package/dist/esm/WorkerSampledChunkSource.d.ts.map +1 -0
  90. package/dist/esm/WorkerSampledChunkSource.js +117 -0
  91. package/dist/esm/WorkerSampledChunkSource.js.map +1 -0
  92. package/dist/esm/autoTile.d.ts +10 -5
  93. package/dist/esm/autoTile.d.ts.map +1 -0
  94. package/dist/esm/autoTile.js +164 -205
  95. package/dist/esm/autoTile.js.map +1 -1
  96. package/dist/esm/chunkGeometry.d.ts +8 -7
  97. package/dist/esm/chunkGeometry.d.ts.map +1 -0
  98. package/dist/esm/chunkGeometry.js +83 -94
  99. package/dist/esm/chunkGeometry.js.map +1 -1
  100. package/dist/esm/index.d.ts +1 -0
  101. package/dist/esm/index.d.ts.map +1 -0
  102. package/dist/esm/index.js +26 -15
  103. package/dist/esm/nodeBounds.d.ts +20 -0
  104. package/dist/esm/nodeBounds.d.ts.map +1 -0
  105. package/dist/esm/nodeBounds.js +40 -0
  106. package/dist/esm/nodeBounds.js.map +1 -0
  107. package/dist/esm/pixelSnap.d.ts +4 -3
  108. package/dist/esm/pixelSnap.d.ts.map +1 -0
  109. package/dist/esm/pixelSnap.js +18 -16
  110. package/dist/esm/pixelSnap.js.map +1 -1
  111. package/dist/esm/public.d.ts +23 -3
  112. package/dist/esm/public.d.ts.map +1 -0
  113. package/dist/esm/tileCollision.d.ts +190 -0
  114. package/dist/esm/tileCollision.d.ts.map +1 -0
  115. package/dist/esm/tileCollision.js +367 -0
  116. package/dist/esm/tileCollision.js.map +1 -0
  117. package/dist/esm/tileWord.d.ts +12 -0
  118. package/dist/esm/tileWord.d.ts.map +1 -0
  119. package/dist/esm/tileWord.js +16 -0
  120. package/dist/esm/tileWord.js.map +1 -0
  121. package/dist/esm/tilemapExtension.d.ts +4 -3
  122. package/dist/esm/tilemapExtension.d.ts.map +1 -0
  123. package/dist/esm/tilemapExtension.js +47 -47
  124. package/dist/esm/tilemapExtension.js.map +1 -1
  125. package/dist/esm/tilemapSerializers.d.ts +5 -4
  126. package/dist/esm/tilemapSerializers.d.ts.map +1 -0
  127. package/dist/esm/tilemapSerializers.js +48 -41
  128. package/dist/esm/tilemapSerializers.js.map +1 -1
  129. package/dist/esm/types.d.ts +34 -18
  130. package/dist/esm/types.d.ts.map +1 -0
  131. package/dist/esm/types.js +111 -120
  132. package/dist/esm/types.js.map +1 -1
  133. package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts +50 -2
  134. package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts.map +1 -0
  135. package/dist/esm/webgl2/WebGl2TileChunkRenderer.js +366 -332
  136. package/dist/esm/webgl2/WebGl2TileChunkRenderer.js.map +1 -1
  137. package/dist/esm/webgl2/shaders/tile-chunk.frag.js +6 -0
  138. package/dist/esm/webgl2/shaders/tile-chunk.frag.js.map +1 -0
  139. package/dist/esm/webgl2/shaders/tile-chunk.vert.js +6 -0
  140. package/dist/esm/webgl2/shaders/tile-chunk.vert.js.map +1 -0
  141. package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts +70 -4
  142. package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts.map +1 -0
  143. package/dist/esm/webgpu/WebGpuTileChunkRenderer.js +496 -383
  144. package/dist/esm/webgpu/WebGpuTileChunkRenderer.js.map +1 -1
  145. package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js +6 -0
  146. package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js.map +1 -0
  147. package/package.json +8 -15
  148. package/dist/esm/index.js.map +0 -1
  149. package/dist/esm/register.d.ts +0 -1
  150. package/dist/esm/register.js +0 -25
  151. package/dist/esm/register.js.map +0 -1
@@ -1,67 +1,74 @@
1
+ //#region src/ImageLayer.ts
1
2
  /**
2
- * A data-only image layer: a single image (texture + resolved URL) placed as a
3
- * background or foreground layer. Image layers are not rendered by the tile
4
- * renderer they are exposed as data for a renderer or follow-up scene node to
5
- * consume.
6
- *
7
- * Parallax, opacity, tint, offset, and repeat flags are carried from the
8
- * source Tiled map.
9
- *
10
- * @advanced
11
- */
12
- class ImageLayer {
13
- /** Layer-kind discriminant. */
14
- kind = 'image';
15
- /** Layer id (unique within the map). */
16
- id;
17
- /** Layer name. */
18
- name;
19
- /** Layer class string. */
20
- class;
21
- /** Resolved URL of the layer image. */
22
- image;
23
- /** Loaded texture for the image, or `null` if unavailable. */
24
- texture;
25
- /** Whether the layer is visible. */
26
- visible;
27
- /** Layer opacity in `[0, 1]`. */
28
- opacity;
29
- /** Layer pixel offset X. */
30
- offsetX;
31
- /** Layer pixel offset Y. */
32
- offsetY;
33
- /** Horizontal parallax factor. */
34
- parallaxX;
35
- /** Vertical parallax factor. */
36
- parallaxY;
37
- /** Tint colour as `0xRRGGBB`, or `null`. */
38
- tintColor;
39
- /** Whether the image repeats horizontally. */
40
- repeatX;
41
- /** Whether the image repeats vertically. */
42
- repeatY;
43
- /** Immutable layer properties. */
44
- properties;
45
- constructor(options) {
46
- this.id = options.id;
47
- this.name = options.name ?? '';
48
- this.class = options.class ?? '';
49
- this.image = options.image;
50
- this.texture = options.texture ?? null;
51
- this.visible = options.visible ?? true;
52
- this.opacity = options.opacity ?? 1;
53
- this.offsetX = options.offsetX ?? 0;
54
- this.offsetY = options.offsetY ?? 0;
55
- this.parallaxX = options.parallaxX ?? 1;
56
- this.parallaxY = options.parallaxY ?? 1;
57
- this.tintColor = options.tintColor ?? null;
58
- this.repeatX = options.repeatX ?? false;
59
- this.repeatY = options.repeatY ?? false;
60
- this.properties = options.properties
61
- ? Object.freeze({ ...options.properties })
62
- : Object.freeze({});
63
- }
64
- }
3
+ * A data-only image layer: a single image (texture + resolved URL) placed as a
4
+ * background or foreground layer. The layer itself holds no scene-graph state -
5
+ * it is rendered by an {@link import('./ImageLayerNode').ImageLayerNode}, which
6
+ * {@link import('./TileMapNode').TileMapNode} and
7
+ * {@link import('./TileMapView').TileMapView} generate and interleave with tile
8
+ * layers by the map's combined document order
9
+ * ({@link import('./TileMap').TileMap.renderableLayers}).
10
+ *
11
+ * Parallax, opacity, tint, offset, and repeat flags are carried from the
12
+ * source Tiled map.
13
+ *
14
+ * @advanced
15
+ */
16
+ var ImageLayer = class {
17
+ /** Layer-kind discriminant. */
18
+ kind = "image";
19
+ /** Layer id (unique within the map). */
20
+ id;
21
+ /** Layer name. */
22
+ name;
23
+ /** Layer class string. */
24
+ class;
25
+ /** Resolved URL of the layer image. */
26
+ image;
27
+ /** Loaded texture for the image, or `null` if unavailable. */
28
+ texture;
29
+ /** Whether the layer is visible. */
30
+ visible;
31
+ /** Layer opacity in `[0, 1]`. */
32
+ opacity;
33
+ /** Layer pixel offset X. */
34
+ offsetX;
35
+ /** Layer pixel offset Y. */
36
+ offsetY;
37
+ /** Horizontal parallax factor. */
38
+ parallaxX;
39
+ /** Vertical parallax factor. */
40
+ parallaxY;
41
+ /** Uniform scale applied around the layer origin during parallax rendering. */
42
+ parallaxScale;
43
+ /** Tint colour as `0xRRGGBB`, or `null`. */
44
+ tintColor;
45
+ /** Whether the image repeats horizontally. */
46
+ repeatX;
47
+ /** Whether the image repeats vertically. */
48
+ repeatY;
49
+ /** Immutable layer properties. */
50
+ properties;
51
+ constructor(options) {
52
+ this.id = options.id;
53
+ this.name = options.name ?? "";
54
+ this.class = options.class ?? "";
55
+ this.image = options.image;
56
+ this.texture = options.texture ?? null;
57
+ this.visible = options.visible ?? true;
58
+ this.opacity = options.opacity ?? 1;
59
+ this.offsetX = options.offsetX ?? 0;
60
+ this.offsetY = options.offsetY ?? 0;
61
+ this.parallaxX = options.parallaxX ?? 1;
62
+ this.parallaxY = options.parallaxY ?? 1;
63
+ this.parallaxScale = options.parallaxScale ?? 1;
64
+ if (!Number.isFinite(this.parallaxScale) || this.parallaxScale <= 0) throw new Error("ImageLayer parallaxScale must be a positive finite number.");
65
+ this.tintColor = options.tintColor ?? null;
66
+ this.repeatX = options.repeatX ?? false;
67
+ this.repeatY = options.repeatY ?? false;
68
+ this.properties = options.properties ? Object.freeze({ ...options.properties }) : Object.freeze({});
69
+ }
70
+ };
65
71
 
72
+ //#endregion
66
73
  export { ImageLayer };
67
- //# sourceMappingURL=ImageLayer.js.map
74
+ //# sourceMappingURL=ImageLayer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ImageLayer.js","sources":["../../../src/ImageLayer.ts"],"sourcesContent":[null],"names":[],"mappings":"AAsCA;;;;;;;;;;AAUG;MACU,UAAU,CAAA;;IAEL,IAAI,GAAG,OAAgB;;AAGvB,IAAA,EAAE;;AAEF,IAAA,IAAI;;AAEJ,IAAA,KAAK;;AAEL,IAAA,KAAK;;AAEL,IAAA,OAAO;;AAEP,IAAA,OAAO;;AAEP,IAAA,OAAO;;AAEP,IAAA,OAAO;;AAEP,IAAA,OAAO;;AAEP,IAAA,SAAS;;AAET,IAAA,SAAS;;AAET,IAAA,SAAS;;AAET,IAAA,OAAO;;AAEP,IAAA,OAAO;;AAEP,IAAA,UAAU;AAE1B,IAAA,WAAA,CAAmB,OAA0B,EAAA;AAC3C,QAAA,IAAI,CAAC,EAAE,GAAG,OAAO,CAAC,EAAE;QACpB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,EAAE;QAC9B,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,EAAE;AAChC,QAAA,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI;QACtC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,IAAI;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK;QACvC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK;AACvC,QAAA,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC;cACtB,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE;AACzC,cAAE,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;IACvB;AACD;;;;"}
1
+ {"version":3,"file":"ImageLayer.js","names":[],"sources":["../../src/ImageLayer.ts"],"sourcesContent":["import type { Texture } from '@codexo/exojs';\n\nimport type { TileProperties } from './types';\n\n/** Construction options for an {@link ImageLayer}. */\nexport interface ImageLayerOptions {\n /** Layer id (unique within the map). */\n readonly id: number;\n /** Layer name. */\n readonly name?: string;\n /** Layer class string. */\n readonly class?: string;\n /** Resolved image URL. */\n readonly image: string;\n /** Loaded texture for the image, or `null` if unavailable. */\n readonly texture?: Texture | null;\n /** Whether the layer is visible. Default `true`. */\n readonly visible?: boolean;\n /** Layer opacity in `[0, 1]`. Default `1`. */\n readonly opacity?: number;\n /** Layer pixel offset X. Default `0`. */\n readonly offsetX?: number;\n /** Layer pixel offset Y. Default `0`. */\n readonly offsetY?: number;\n /** Horizontal parallax factor. Default `1`. */\n readonly parallaxX?: number;\n /** Vertical parallax factor. Default `1`. */\n readonly parallaxY?: number;\n /** Uniform parallax scale around the layer origin. Default `1`. */\n readonly parallaxScale?: number;\n /** Tint colour as `0xRRGGBB`, or `null`. Default `null`. */\n readonly tintColor?: number | null;\n /** Whether the image repeats horizontally. Default `false`. */\n readonly repeatX?: boolean;\n /** Whether the image repeats vertically. Default `false`. */\n readonly repeatY?: boolean;\n /** Layer properties (copied and frozen). */\n readonly properties?: TileProperties;\n}\n\n/**\n * A data-only image layer: a single image (texture + resolved URL) placed as a\n * background or foreground layer. The layer itself holds no scene-graph state -\n * it is rendered by an {@link import('./ImageLayerNode').ImageLayerNode}, which\n * {@link import('./TileMapNode').TileMapNode} and\n * {@link import('./TileMapView').TileMapView} generate and interleave with tile\n * layers by the map's combined document order\n * ({@link import('./TileMap').TileMap.renderableLayers}).\n *\n * Parallax, opacity, tint, offset, and repeat flags are carried from the\n * source Tiled map.\n *\n * @advanced\n */\nexport class ImageLayer {\n /** Layer-kind discriminant. */\n public readonly kind = 'image' as const;\n\n /** Layer id (unique within the map). */\n public readonly id: number;\n /** Layer name. */\n public readonly name: string;\n /** Layer class string. */\n public readonly class: string;\n /** Resolved URL of the layer image. */\n public readonly image: string;\n /** Loaded texture for the image, or `null` if unavailable. */\n public readonly texture: Texture | null;\n /** Whether the layer is visible. */\n public readonly visible: boolean;\n /** Layer opacity in `[0, 1]`. */\n public readonly opacity: number;\n /** Layer pixel offset X. */\n public readonly offsetX: number;\n /** Layer pixel offset Y. */\n public readonly offsetY: number;\n /** Horizontal parallax factor. */\n public readonly parallaxX: number;\n /** Vertical parallax factor. */\n public readonly parallaxY: number;\n /** Uniform scale applied around the layer origin during parallax rendering. */\n public readonly parallaxScale: number;\n /** Tint colour as `0xRRGGBB`, or `null`. */\n public readonly tintColor: number | null;\n /** Whether the image repeats horizontally. */\n public readonly repeatX: boolean;\n /** Whether the image repeats vertically. */\n public readonly repeatY: boolean;\n /** Immutable layer properties. */\n public readonly properties: TileProperties;\n\n public constructor(options: ImageLayerOptions) {\n this.id = options.id;\n this.name = options.name ?? '';\n this.class = options.class ?? '';\n this.image = options.image;\n this.texture = options.texture ?? null;\n this.visible = options.visible ?? true;\n this.opacity = options.opacity ?? 1;\n this.offsetX = options.offsetX ?? 0;\n this.offsetY = options.offsetY ?? 0;\n this.parallaxX = options.parallaxX ?? 1;\n this.parallaxY = options.parallaxY ?? 1;\n this.parallaxScale = options.parallaxScale ?? 1;\n if (!Number.isFinite(this.parallaxScale) || this.parallaxScale <= 0) {\n throw new Error('ImageLayer parallaxScale must be a positive finite number.');\n }\n this.tintColor = options.tintColor ?? null;\n this.repeatX = options.repeatX ?? false;\n this.repeatY = options.repeatY ?? false;\n this.properties = options.properties ? Object.freeze({ ...options.properties }) : Object.freeze({});\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAsDA,IAAa,aAAb,MAAwB;;CAEtB,AAAgB,OAAO;;CAGvB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;CAEhB,AAAO,YAAY,SAA4B;EAC7C,KAAK,KAAK,QAAQ;EAClB,KAAK,OAAO,QAAQ,QAAQ;EAC5B,KAAK,QAAQ,QAAQ,SAAS;EAC9B,KAAK,QAAQ,QAAQ;EACrB,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,YAAY,QAAQ,aAAa;EACtC,KAAK,YAAY,QAAQ,aAAa;EACtC,KAAK,gBAAgB,QAAQ,iBAAiB;EAC9C,IAAI,CAAC,OAAO,SAAS,KAAK,aAAa,KAAK,KAAK,iBAAiB,GAChE,MAAM,IAAI,MAAM,4DAA4D;EAE9E,KAAK,YAAY,QAAQ,aAAa;EACtC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,UAAU,QAAQ,WAAW;EAClC,KAAK,aAAa,QAAQ,aAAa,OAAO,OAAO,EAAE,GAAG,QAAQ,WAAW,CAAC,IAAI,OAAO,OAAO,CAAC,CAAC;CACpG;AACF"}
@@ -0,0 +1,89 @@
1
+ import { Container } from '@codexo/exojs';
2
+ import { PixelSnapMode, type RenderPlanBuilder } from '@codexo/exojs/renderer-sdk';
3
+ import type { ImageLayer } from './ImageLayer';
4
+ /**
5
+ * A scene node that renders one Tiled {@link ImageLayer} as a single
6
+ * {@link RepeatingSprite} wrapped in a {@link Container}.
7
+ *
8
+ * The layer's pixel `offset` becomes this node's position; `parallax` is
9
+ * resolved per frame in {@link _collectContent} by patching the node position
10
+ * against the camera centre (exactly like {@link import('./TileLayerNode').TileLayerNode}),
11
+ * then restoring it. When `repeatX`/`repeatY` is set the wrapped sprite is
12
+ * grown each frame to cover the visible view with a period-aligned origin, so
13
+ * the pattern tiles seamlessly and scrolls with parallax. A repeat axis or a
14
+ * `parallax` factor other than `1` both make this node's rendered position
15
+ * and/or size camera-dependent at collect time, so its static bounds cannot be
16
+ * culled against - such a node opts out of view culling (`cullable = false`).
17
+ *
18
+ * `visible`, `opacity`, and `tintColor` are applied **once at construction**:
19
+ * {@link ImageLayer} is immutable, so there is nothing to re-sync per frame.
20
+ * A layer whose `texture` is `null` (image failed to load / not yet available)
21
+ * produces an empty node with no children - it occupies its offset in the
22
+ * scene graph but draws nothing.
23
+ *
24
+ * The node references - but never owns - the {@link ImageLayer} and its
25
+ * Loader-owned texture: {@link destroy} frees the wrapped sprite but leaves the
26
+ * layer and texture intact. Image-layer nodes are band-selectable exactly like
27
+ * tile-layer nodes: list the image layer in a
28
+ * {@link import('./TileMapView').TileMapViewOptions.bands} definition and the
29
+ * band stacks it by the map's combined document order, or parent an unbanded
30
+ * node into the scene directly wherever the image belongs in draw order.
31
+ *
32
+ * For a `repeatX`/`repeatY` node, bounds and hit-test queries reflect the
33
+ * coverage geometry computed by the last {@link _collectContent} call (since
34
+ * that geometry is recomputed per collect, not maintained incrementally),
35
+ * which is also why such a node force-disables `cullable`. A repeating or
36
+ * parallax node also re-sizes its wrapped sprite as the camera crosses period
37
+ * boundaries, which content-dirties an enclosing retained group the same way
38
+ * a streamed layer does - give it the same treatment (its own
39
+ * `RetainedContainer`, or none).
40
+ *
41
+ * @advanced
42
+ */
43
+ export declare class ImageLayerNode extends Container {
44
+ private readonly _layer;
45
+ private readonly _sprite;
46
+ private readonly _baseOffsetX;
47
+ private readonly _baseOffsetY;
48
+ private readonly _imageWidth;
49
+ private readonly _imageHeight;
50
+ private _pixelSnapMode;
51
+ private _covViewX;
52
+ private _covViewY;
53
+ private _covViewWidth;
54
+ private _covViewHeight;
55
+ private _covOriginX;
56
+ private _covOriginY;
57
+ constructor(layer: ImageLayer);
58
+ /** The runtime layer this node renders. */
59
+ get layer(): ImageLayer;
60
+ /**
61
+ * Render-only pixel-snap mode forwarded to the wrapped {@link RepeatingSprite}
62
+ * (which snaps its rendered origin, and - in `PixelSnapMode.Geometry` mode for
63
+ * axis-aligned transforms - its repeat-segment boundaries, to the render
64
+ * target's device-pixel grid). Purely visual: the layer offset, parallax, and
65
+ * repeat coverage are never changed.
66
+ *
67
+ * For a `null`-texture layer there is no drawable to forward to, so the mode
68
+ * is simply stored. Setting the current value is a no-op; an invalid value
69
+ * throws and leaves the prior mode unchanged.
70
+ *
71
+ * @default PixelSnapMode.None
72
+ * @stable
73
+ */
74
+ get pixelSnapMode(): PixelSnapMode;
75
+ set pixelSnapMode(mode: PixelSnapMode);
76
+ /** @internal */
77
+ protected _collectContent(builder: RenderPlanBuilder): void;
78
+ destroy(): void;
79
+ /**
80
+ * Grow the wrapped sprite along each repeating axis so it covers the visible
81
+ * view, with a period-aligned local origin so the pattern offset stays zero
82
+ * (seamless tiling). Non-repeating axes keep the natural image size at local
83
+ * `0`. Reads `this.x`/`this.y` after the parallax patch, so the pattern anchor
84
+ * follows the parallax-shifted origin. Skips the rebuild when neither the view
85
+ * span nor the patched origin changed since the last frame.
86
+ */
87
+ private _updateRepeatCoverage;
88
+ }
89
+ //# sourceMappingURL=ImageLayerNode.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageLayerNode.d.ts","sourceRoot":"","sources":["../../src/ImageLayerNode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmB,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAEnF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBAAa,cAAe,SAAQ,SAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,cAAc,CAAqC;IAI3D,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,aAAa,CAAc;IACnC,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,WAAW,CAAc;gBAEd,KAAK,EAAE,UAAU;IAgDpC,2CAA2C;IAC3C,IAAW,KAAK,IAAI,UAAU,CAE7B;IAED;;;;;;;;;;;;;OAaG;IACH,IAAW,aAAa,IAAI,aAAa,CAExC;IAED,IAAW,aAAa,CAAC,IAAI,EAAE,aAAa,EAW3C;IAED,gBAAgB;cACG,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IA8CpD,OAAO,IAAI,IAAI;IAQ/B;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;CA4D9B"}
@@ -0,0 +1,205 @@
1
+ import { assertPixelSnapMode } from "./pixelSnap.js";
2
+ import { PixelSnapMode } from "@codexo/exojs/renderer-sdk";
3
+ import { Container, RepeatingSprite } from "@codexo/exojs";
4
+
5
+ //#region src/ImageLayerNode.ts
6
+ /**
7
+ * A scene node that renders one Tiled {@link ImageLayer} as a single
8
+ * {@link RepeatingSprite} wrapped in a {@link Container}.
9
+ *
10
+ * The layer's pixel `offset` becomes this node's position; `parallax` is
11
+ * resolved per frame in {@link _collectContent} by patching the node position
12
+ * against the camera centre (exactly like {@link import('./TileLayerNode').TileLayerNode}),
13
+ * then restoring it. When `repeatX`/`repeatY` is set the wrapped sprite is
14
+ * grown each frame to cover the visible view with a period-aligned origin, so
15
+ * the pattern tiles seamlessly and scrolls with parallax. A repeat axis or a
16
+ * `parallax` factor other than `1` both make this node's rendered position
17
+ * and/or size camera-dependent at collect time, so its static bounds cannot be
18
+ * culled against - such a node opts out of view culling (`cullable = false`).
19
+ *
20
+ * `visible`, `opacity`, and `tintColor` are applied **once at construction**:
21
+ * {@link ImageLayer} is immutable, so there is nothing to re-sync per frame.
22
+ * A layer whose `texture` is `null` (image failed to load / not yet available)
23
+ * produces an empty node with no children - it occupies its offset in the
24
+ * scene graph but draws nothing.
25
+ *
26
+ * The node references - but never owns - the {@link ImageLayer} and its
27
+ * Loader-owned texture: {@link destroy} frees the wrapped sprite but leaves the
28
+ * layer and texture intact. Image-layer nodes are band-selectable exactly like
29
+ * tile-layer nodes: list the image layer in a
30
+ * {@link import('./TileMapView').TileMapViewOptions.bands} definition and the
31
+ * band stacks it by the map's combined document order, or parent an unbanded
32
+ * node into the scene directly wherever the image belongs in draw order.
33
+ *
34
+ * For a `repeatX`/`repeatY` node, bounds and hit-test queries reflect the
35
+ * coverage geometry computed by the last {@link _collectContent} call (since
36
+ * that geometry is recomputed per collect, not maintained incrementally),
37
+ * which is also why such a node force-disables `cullable`. A repeating or
38
+ * parallax node also re-sizes its wrapped sprite as the camera crosses period
39
+ * boundaries, which content-dirties an enclosing retained group the same way
40
+ * a streamed layer does - give it the same treatment (its own
41
+ * `RetainedContainer`, or none).
42
+ *
43
+ * @advanced
44
+ */
45
+ var ImageLayerNode = class extends Container {
46
+ _layer;
47
+ _sprite;
48
+ _baseOffsetX;
49
+ _baseOffsetY;
50
+ _imageWidth;
51
+ _imageHeight;
52
+ _pixelSnapMode = PixelSnapMode.None;
53
+ _covViewX = NaN;
54
+ _covViewY = NaN;
55
+ _covViewWidth = NaN;
56
+ _covViewHeight = NaN;
57
+ _covOriginX = NaN;
58
+ _covOriginY = NaN;
59
+ constructor(layer) {
60
+ super();
61
+ this._layer = layer;
62
+ this._baseOffsetX = layer.offsetX;
63
+ this._baseOffsetY = layer.offsetY;
64
+ this.setPosition(layer.offsetX, layer.offsetY);
65
+ this.visible = layer.visible;
66
+ const texture = layer.texture;
67
+ if (texture === null) {
68
+ this._sprite = null;
69
+ this._imageWidth = 0;
70
+ this._imageHeight = 0;
71
+ return;
72
+ }
73
+ this._imageWidth = texture.width;
74
+ this._imageHeight = texture.height;
75
+ const sprite = new RepeatingSprite(texture, {
76
+ modeX: layer.repeatX ? "repeat" : "stretch",
77
+ modeY: layer.repeatY ? "repeat" : "stretch",
78
+ width: texture.width,
79
+ height: texture.height
80
+ });
81
+ const tintColor = layer.tintColor;
82
+ const r = tintColor === null ? 255 : tintColor >> 16 & 255;
83
+ const g = tintColor === null ? 255 : tintColor >> 8 & 255;
84
+ const b = tintColor === null ? 255 : tintColor & 255;
85
+ sprite.tint.set(r, g, b, layer.opacity);
86
+ this._sprite = sprite;
87
+ this.addChild(sprite);
88
+ if (layer.repeatX || layer.repeatY || layer.parallaxX !== 1 || layer.parallaxY !== 1 || layer.parallaxScale !== 1) this.cullable = false;
89
+ }
90
+ /** The runtime layer this node renders. */
91
+ get layer() {
92
+ return this._layer;
93
+ }
94
+ /**
95
+ * Render-only pixel-snap mode forwarded to the wrapped {@link RepeatingSprite}
96
+ * (which snaps its rendered origin, and - in `PixelSnapMode.Geometry` mode for
97
+ * axis-aligned transforms - its repeat-segment boundaries, to the render
98
+ * target's device-pixel grid). Purely visual: the layer offset, parallax, and
99
+ * repeat coverage are never changed.
100
+ *
101
+ * For a `null`-texture layer there is no drawable to forward to, so the mode
102
+ * is simply stored. Setting the current value is a no-op; an invalid value
103
+ * throws and leaves the prior mode unchanged.
104
+ *
105
+ * @default PixelSnapMode.None
106
+ * @stable
107
+ */
108
+ get pixelSnapMode() {
109
+ return this._pixelSnapMode;
110
+ }
111
+ set pixelSnapMode(mode) {
112
+ if (mode === this._pixelSnapMode) return;
113
+ assertPixelSnapMode(mode);
114
+ this._pixelSnapMode = mode;
115
+ if (this._sprite !== null) this._sprite.pixelSnapMode = mode;
116
+ }
117
+ /** @internal */
118
+ _collectContent(builder) {
119
+ if (this._sprite === null) {
120
+ super._collectContent(builder);
121
+ return;
122
+ }
123
+ const layer = this._layer;
124
+ const patchesPosition = layer.parallaxX !== 1 || layer.parallaxY !== 1;
125
+ const patchesScale = layer.parallaxScale !== 1;
126
+ if (patchesPosition || patchesScale) {
127
+ const camCenter = builder.view.center;
128
+ const prevX = this.x;
129
+ const prevY = this.y;
130
+ const prevScaleX = this.scale.x;
131
+ const prevScaleY = this.scale.y;
132
+ if (patchesPosition) {
133
+ this.x = this._baseOffsetX + camCenter.x * (1 - layer.parallaxX);
134
+ this.y = this._baseOffsetY + camCenter.y * (1 - layer.parallaxY);
135
+ }
136
+ if (patchesScale) this.setScale(prevScaleX * layer.parallaxScale, prevScaleY * layer.parallaxScale);
137
+ try {
138
+ this._updateRepeatCoverage(builder, layer.parallaxScale);
139
+ super._collectContent(builder);
140
+ } finally {
141
+ if (patchesPosition) this.setPosition(prevX, prevY);
142
+ if (patchesScale) this.setScale(prevScaleX, prevScaleY);
143
+ }
144
+ } else {
145
+ this._updateRepeatCoverage(builder);
146
+ super._collectContent(builder);
147
+ }
148
+ }
149
+ destroy() {
150
+ const sprite = this._sprite;
151
+ super.destroy();
152
+ sprite?.destroy();
153
+ }
154
+ /**
155
+ * Grow the wrapped sprite along each repeating axis so it covers the visible
156
+ * view, with a period-aligned local origin so the pattern offset stays zero
157
+ * (seamless tiling). Non-repeating axes keep the natural image size at local
158
+ * `0`. Reads `this.x`/`this.y` after the parallax patch, so the pattern anchor
159
+ * follows the parallax-shifted origin. Skips the rebuild when neither the view
160
+ * span nor the patched origin changed since the last frame.
161
+ */
162
+ _updateRepeatCoverage(builder, parallaxScale = 1) {
163
+ const layer = this._layer;
164
+ const sprite = this._sprite;
165
+ if (sprite === null || !layer.repeatX && !layer.repeatY) return;
166
+ const bounds = builder.view.getBounds();
167
+ const originX = this.x;
168
+ const originY = this.y;
169
+ if (bounds.x === this._covViewX && bounds.y === this._covViewY && bounds.width === this._covViewWidth && bounds.height === this._covViewHeight && originX === this._covOriginX && originY === this._covOriginY) return;
170
+ this._covViewX = bounds.x;
171
+ this._covViewY = bounds.y;
172
+ this._covViewWidth = bounds.width;
173
+ this._covViewHeight = bounds.height;
174
+ this._covOriginX = originX;
175
+ this._covOriginY = originY;
176
+ let childX = 0;
177
+ let childY = 0;
178
+ let childWidth = this._imageWidth;
179
+ let childHeight = this._imageHeight;
180
+ if (layer.repeatX) {
181
+ const imgW = this._imageWidth;
182
+ const localViewMin = (bounds.x - originX) / parallaxScale;
183
+ const localViewWidth = bounds.width / parallaxScale;
184
+ const startLocal = Math.floor(localViewMin / imgW) * imgW;
185
+ const periods = Math.ceil((localViewMin + localViewWidth - startLocal) / imgW);
186
+ childX = startLocal;
187
+ childWidth = periods * imgW;
188
+ }
189
+ if (layer.repeatY) {
190
+ const imgH = this._imageHeight;
191
+ const localViewMin = (bounds.y - originY) / parallaxScale;
192
+ const localViewHeight = bounds.height / parallaxScale;
193
+ const startLocal = Math.floor(localViewMin / imgH) * imgH;
194
+ const periods = Math.ceil((localViewMin + localViewHeight - startLocal) / imgH);
195
+ childY = startLocal;
196
+ childHeight = periods * imgH;
197
+ }
198
+ sprite.setPosition(childX, childY);
199
+ sprite.setSize(childWidth, childHeight);
200
+ }
201
+ };
202
+
203
+ //#endregion
204
+ export { ImageLayerNode };
205
+ //# sourceMappingURL=ImageLayerNode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ImageLayerNode.js","names":[],"sources":["../../src/ImageLayerNode.ts"],"sourcesContent":["import { Container, RepeatingSprite } from '@codexo/exojs';\nimport { PixelSnapMode, type RenderPlanBuilder } from '@codexo/exojs/renderer-sdk';\n\nimport type { ImageLayer } from './ImageLayer';\nimport { assertPixelSnapMode } from './pixelSnap';\n\n/**\n * A scene node that renders one Tiled {@link ImageLayer} as a single\n * {@link RepeatingSprite} wrapped in a {@link Container}.\n *\n * The layer's pixel `offset` becomes this node's position; `parallax` is\n * resolved per frame in {@link _collectContent} by patching the node position\n * against the camera centre (exactly like {@link import('./TileLayerNode').TileLayerNode}),\n * then restoring it. When `repeatX`/`repeatY` is set the wrapped sprite is\n * grown each frame to cover the visible view with a period-aligned origin, so\n * the pattern tiles seamlessly and scrolls with parallax. A repeat axis or a\n * `parallax` factor other than `1` both make this node's rendered position\n * and/or size camera-dependent at collect time, so its static bounds cannot be\n * culled against - such a node opts out of view culling (`cullable = false`).\n *\n * `visible`, `opacity`, and `tintColor` are applied **once at construction**:\n * {@link ImageLayer} is immutable, so there is nothing to re-sync per frame.\n * A layer whose `texture` is `null` (image failed to load / not yet available)\n * produces an empty node with no children - it occupies its offset in the\n * scene graph but draws nothing.\n *\n * The node references - but never owns - the {@link ImageLayer} and its\n * Loader-owned texture: {@link destroy} frees the wrapped sprite but leaves the\n * layer and texture intact. Image-layer nodes are band-selectable exactly like\n * tile-layer nodes: list the image layer in a\n * {@link import('./TileMapView').TileMapViewOptions.bands} definition and the\n * band stacks it by the map's combined document order, or parent an unbanded\n * node into the scene directly wherever the image belongs in draw order.\n *\n * For a `repeatX`/`repeatY` node, bounds and hit-test queries reflect the\n * coverage geometry computed by the last {@link _collectContent} call (since\n * that geometry is recomputed per collect, not maintained incrementally),\n * which is also why such a node force-disables `cullable`. A repeating or\n * parallax node also re-sizes its wrapped sprite as the camera crosses period\n * boundaries, which content-dirties an enclosing retained group the same way\n * a streamed layer does - give it the same treatment (its own\n * `RetainedContainer`, or none).\n *\n * @advanced\n */\nexport class ImageLayerNode extends Container {\n private readonly _layer: ImageLayer;\n private readonly _sprite: RepeatingSprite | null;\n private readonly _baseOffsetX: number;\n private readonly _baseOffsetY: number;\n private readonly _imageWidth: number;\n private readonly _imageHeight: number;\n private _pixelSnapMode: PixelSnapMode = PixelSnapMode.None;\n\n // Repeat-coverage cache: the view span and patched origin that last drove a\n // resize. A static camera pays one comparison per frame and skips the rebuild.\n private _covViewX = Number.NaN;\n private _covViewY = Number.NaN;\n private _covViewWidth = Number.NaN;\n private _covViewHeight = Number.NaN;\n private _covOriginX = Number.NaN;\n private _covOriginY = Number.NaN;\n\n public constructor(layer: ImageLayer) {\n super();\n\n this._layer = layer;\n this._baseOffsetX = layer.offsetX;\n this._baseOffsetY = layer.offsetY;\n\n this.setPosition(layer.offsetX, layer.offsetY);\n this.visible = layer.visible;\n\n const texture = layer.texture;\n\n if (texture === null) {\n this._sprite = null;\n this._imageWidth = 0;\n this._imageHeight = 0;\n\n return;\n }\n\n this._imageWidth = texture.width;\n this._imageHeight = texture.height;\n\n // Non-repeating axes use `'stretch'` so the axis shows exactly one un-tiled\n // copy at its natural size; repeating axes use `'repeat'` and are grown to\n // cover the view in `_collectContent`.\n const sprite = new RepeatingSprite(texture, {\n modeX: layer.repeatX ? 'repeat' : 'stretch',\n modeY: layer.repeatY ? 'repeat' : 'stretch',\n width: texture.width,\n height: texture.height,\n });\n\n const tintColor = layer.tintColor;\n const r = tintColor === null ? 255 : (tintColor >> 16) & 0xff;\n const g = tintColor === null ? 255 : (tintColor >> 8) & 0xff;\n const b = tintColor === null ? 255 : tintColor & 0xff;\n\n sprite.tint.set(r, g, b, layer.opacity);\n\n this._sprite = sprite;\n this.addChild(sprite);\n\n if (layer.repeatX || layer.repeatY || layer.parallaxX !== 1 || layer.parallaxY !== 1 || layer.parallaxScale !== 1) {\n this.cullable = false;\n }\n }\n\n /** The runtime layer this node renders. */\n public get layer(): ImageLayer {\n return this._layer;\n }\n\n /**\n * Render-only pixel-snap mode forwarded to the wrapped {@link RepeatingSprite}\n * (which snaps its rendered origin, and - in `PixelSnapMode.Geometry` mode for\n * axis-aligned transforms - its repeat-segment boundaries, to the render\n * target's device-pixel grid). Purely visual: the layer offset, parallax, and\n * repeat coverage are never changed.\n *\n * For a `null`-texture layer there is no drawable to forward to, so the mode\n * is simply stored. Setting the current value is a no-op; an invalid value\n * throws and leaves the prior mode unchanged.\n *\n * @default PixelSnapMode.None\n * @stable\n */\n public get pixelSnapMode(): PixelSnapMode {\n return this._pixelSnapMode;\n }\n\n public set pixelSnapMode(mode: PixelSnapMode) {\n if (mode === this._pixelSnapMode) {\n return;\n }\n\n assertPixelSnapMode(mode);\n this._pixelSnapMode = mode;\n\n if (this._sprite !== null) {\n this._sprite.pixelSnapMode = mode;\n }\n }\n\n /** @internal */\n protected override _collectContent(builder: RenderPlanBuilder): void {\n if (this._sprite === null) {\n super._collectContent(builder);\n\n return;\n }\n\n const layer = this._layer;\n\n const patchesPosition = layer.parallaxX !== 1 || layer.parallaxY !== 1;\n const patchesScale = layer.parallaxScale !== 1;\n\n if (patchesPosition || patchesScale) {\n const camCenter = builder.view.center;\n const prevX = this.x;\n const prevY = this.y;\n const prevScaleX = this.scale.x;\n const prevScaleY = this.scale.y;\n\n if (patchesPosition) {\n this.x = this._baseOffsetX + camCenter.x * (1 - layer.parallaxX);\n this.y = this._baseOffsetY + camCenter.y * (1 - layer.parallaxY);\n }\n\n if (patchesScale) {\n this.setScale(prevScaleX * layer.parallaxScale, prevScaleY * layer.parallaxScale);\n }\n\n try {\n this._updateRepeatCoverage(builder, layer.parallaxScale);\n super._collectContent(builder);\n } finally {\n if (patchesPosition) {\n this.setPosition(prevX, prevY);\n }\n\n if (patchesScale) {\n this.setScale(prevScaleX, prevScaleY);\n }\n }\n } else {\n this._updateRepeatCoverage(builder);\n super._collectContent(builder);\n }\n }\n\n public override destroy(): void {\n const sprite = this._sprite;\n\n super.destroy();\n\n sprite?.destroy();\n }\n\n /**\n * Grow the wrapped sprite along each repeating axis so it covers the visible\n * view, with a period-aligned local origin so the pattern offset stays zero\n * (seamless tiling). Non-repeating axes keep the natural image size at local\n * `0`. Reads `this.x`/`this.y` after the parallax patch, so the pattern anchor\n * follows the parallax-shifted origin. Skips the rebuild when neither the view\n * span nor the patched origin changed since the last frame.\n */\n private _updateRepeatCoverage(builder: RenderPlanBuilder, parallaxScale = 1): void {\n const layer = this._layer;\n const sprite = this._sprite;\n\n if (sprite === null || (!layer.repeatX && !layer.repeatY)) {\n return;\n }\n\n const bounds = builder.view.getBounds();\n const originX = this.x;\n const originY = this.y;\n\n if (\n bounds.x === this._covViewX &&\n bounds.y === this._covViewY &&\n bounds.width === this._covViewWidth &&\n bounds.height === this._covViewHeight &&\n originX === this._covOriginX &&\n originY === this._covOriginY\n ) {\n return;\n }\n\n this._covViewX = bounds.x;\n this._covViewY = bounds.y;\n this._covViewWidth = bounds.width;\n this._covViewHeight = bounds.height;\n this._covOriginX = originX;\n this._covOriginY = originY;\n\n let childX = 0;\n let childY = 0;\n let childWidth = this._imageWidth;\n let childHeight = this._imageHeight;\n\n if (layer.repeatX) {\n const imgW = this._imageWidth;\n const localViewMin = (bounds.x - originX) / parallaxScale;\n const localViewWidth = bounds.width / parallaxScale;\n const startLocal = Math.floor(localViewMin / imgW) * imgW;\n const periods = Math.ceil((localViewMin + localViewWidth - startLocal) / imgW);\n\n childX = startLocal;\n childWidth = periods * imgW;\n }\n\n if (layer.repeatY) {\n const imgH = this._imageHeight;\n const localViewMin = (bounds.y - originY) / parallaxScale;\n const localViewHeight = bounds.height / parallaxScale;\n const startLocal = Math.floor(localViewMin / imgH) * imgH;\n const periods = Math.ceil((localViewMin + localViewHeight - startLocal) / imgH);\n\n childY = startLocal;\n childHeight = periods * imgH;\n }\n\n sprite.setPosition(childX, childY);\n sprite.setSize(childWidth, childHeight);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ import type { ObjectLayer, TileMapObject } from './ObjectLayer';
2
+ import type { TileMap } from './TileMap';
3
+ import type { TileProperties } from './types';
4
+ /**
5
+ * A format-neutral view of one map object, as handed to a
6
+ * {@link import('./MapObjectSpawner').MapObjectFactory}.
7
+ *
8
+ * The descriptor is what game code writes against: it resolves the two things
9
+ * that differ between authoring formats - stable identity and the dispatch
10
+ * key - and pairs the object with the layer it came from. The parsed object
11
+ * itself stays reachable through {@link object}, and the untouched source
12
+ * record through {@link TileMapObject.source}.
13
+ */
14
+ export interface MapObjectDescriptor {
15
+ /**
16
+ * Stable identity for this object.
17
+ *
18
+ * Uniqueness domain is **one {@link TileMap}**: Tiled object ids are unique
19
+ * within a map, and LDtk entity iids are unique globally, so an LDtk-sourced
20
+ * id keeps that stronger guarantee. Combine with the owning level's id if a
21
+ * world-wide key is needed.
22
+ *
23
+ * Derived from {@link TileMapObject.sourceId} when the format supplies one,
24
+ * otherwise from the numeric {@link TileMapObject.id}.
25
+ */
26
+ readonly id: string;
27
+ /**
28
+ * Canonical dispatch key - the object's class/type string, or `null` when the
29
+ * source declares none.
30
+ *
31
+ * LDtk fills it with the entity definition identifier, Tiled with the
32
+ * object's class. A {@link import('./MapObjectSpawner').MapObjectSpawner}
33
+ * uses it to pick a factory unless an `identify` strategy overrides that.
34
+ */
35
+ readonly kind: string | null;
36
+ /** Object name; may be empty and is not unique. */
37
+ readonly name: string;
38
+ /** X of the object origin in object-layer pixel space. */
39
+ readonly x: number;
40
+ /** Y of the object origin in object-layer pixel space. */
41
+ readonly y: number;
42
+ /** Bounding width in px (0 for points). */
43
+ readonly width: number;
44
+ /** Bounding height in px (0 for points). */
45
+ readonly height: number;
46
+ /** Rotation in degrees, clockwise. See {@link TileMapObject} for the pivot. */
47
+ readonly rotation: number;
48
+ /** The object's immutable custom properties. */
49
+ readonly properties: TileProperties;
50
+ /** The object layer this object was authored on, with its placement metadata. */
51
+ readonly layer: ObjectLayer;
52
+ /** The parsed object itself - narrow on `object.kind` to read geometry. */
53
+ readonly object: TileMapObject;
54
+ }
55
+ /**
56
+ * Build the {@link MapObjectDescriptor} for one object of `layer`.
57
+ *
58
+ * Exposed for code that spawns from a hand-picked object rather than from a
59
+ * whole map; {@link mapObjectDescriptors} covers the common case.
60
+ */
61
+ export declare const mapObjectDescriptor: (object: TileMapObject, layer: ObjectLayer) => MapObjectDescriptor;
62
+ /**
63
+ * Every object of `map`, in a defined order: object-layer order first, then
64
+ * object order within each layer.
65
+ *
66
+ * This is the order a {@link import('./MapObjectSpawner').MapObjectSpawner}
67
+ * spawns in, so the same map always produces the same sequence.
68
+ */
69
+ export declare const mapObjectDescriptors: (map: TileMap) => Generator<MapObjectDescriptor>;
70
+ //# sourceMappingURL=MapObject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapObject.d.ts","sourceRoot":"","sources":["../../src/MapObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C;;;;;;;;;GASG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB;;;;;;;OAOG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,4CAA4C;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,+EAA+E;IAC/E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,gDAAgD;IAChD,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC;IACpC,iFAAiF;IACjF,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;CAChC;AAED;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,aAAa,EAAE,OAAO,WAAW,KAAG,mBAY9E,CAAC;AAEH;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAc,KAAK,OAAO,KAAG,SAAS,CAAC,mBAAmB,CAM1F,CAAC"}
@@ -0,0 +1,34 @@
1
+ //#region src/MapObject.ts
2
+ /**
3
+ * Build the {@link MapObjectDescriptor} for one object of `layer`.
4
+ *
5
+ * Exposed for code that spawns from a hand-picked object rather than from a
6
+ * whole map; {@link mapObjectDescriptors} covers the common case.
7
+ */
8
+ const mapObjectDescriptor = (object, layer) => ({
9
+ id: object.sourceId ?? String(object.id),
10
+ kind: object.type === "" ? null : object.type,
11
+ name: object.name,
12
+ x: object.x,
13
+ y: object.y,
14
+ width: object.width,
15
+ height: object.height,
16
+ rotation: object.rotation,
17
+ properties: object.properties,
18
+ layer,
19
+ object
20
+ });
21
+ /**
22
+ * Every object of `map`, in a defined order: object-layer order first, then
23
+ * object order within each layer.
24
+ *
25
+ * This is the order a {@link import('./MapObjectSpawner').MapObjectSpawner}
26
+ * spawns in, so the same map always produces the same sequence.
27
+ */
28
+ const mapObjectDescriptors = function* (map) {
29
+ for (const layer of map.objectLayers) for (const object of layer.objects) yield mapObjectDescriptor(object, layer);
30
+ };
31
+
32
+ //#endregion
33
+ export { mapObjectDescriptor, mapObjectDescriptors };
34
+ //# sourceMappingURL=MapObject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapObject.js","names":[],"sources":["../../src/MapObject.ts"],"sourcesContent":["import type { ObjectLayer, TileMapObject } from './ObjectLayer';\nimport type { TileMap } from './TileMap';\nimport type { TileProperties } from './types';\n\n/**\n * A format-neutral view of one map object, as handed to a\n * {@link import('./MapObjectSpawner').MapObjectFactory}.\n *\n * The descriptor is what game code writes against: it resolves the two things\n * that differ between authoring formats - stable identity and the dispatch\n * key - and pairs the object with the layer it came from. The parsed object\n * itself stays reachable through {@link object}, and the untouched source\n * record through {@link TileMapObject.source}.\n */\nexport interface MapObjectDescriptor {\n /**\n * Stable identity for this object.\n *\n * Uniqueness domain is **one {@link TileMap}**: Tiled object ids are unique\n * within a map, and LDtk entity iids are unique globally, so an LDtk-sourced\n * id keeps that stronger guarantee. Combine with the owning level's id if a\n * world-wide key is needed.\n *\n * Derived from {@link TileMapObject.sourceId} when the format supplies one,\n * otherwise from the numeric {@link TileMapObject.id}.\n */\n readonly id: string;\n /**\n * Canonical dispatch key - the object's class/type string, or `null` when the\n * source declares none.\n *\n * LDtk fills it with the entity definition identifier, Tiled with the\n * object's class. A {@link import('./MapObjectSpawner').MapObjectSpawner}\n * uses it to pick a factory unless an `identify` strategy overrides that.\n */\n readonly kind: string | null;\n /** Object name; may be empty and is not unique. */\n readonly name: string;\n /** X of the object origin in object-layer pixel space. */\n readonly x: number;\n /** Y of the object origin in object-layer pixel space. */\n readonly y: number;\n /** Bounding width in px (0 for points). */\n readonly width: number;\n /** Bounding height in px (0 for points). */\n readonly height: number;\n /** Rotation in degrees, clockwise. See {@link TileMapObject} for the pivot. */\n readonly rotation: number;\n /** The object's immutable custom properties. */\n readonly properties: TileProperties;\n /** The object layer this object was authored on, with its placement metadata. */\n readonly layer: ObjectLayer;\n /** The parsed object itself - narrow on `object.kind` to read geometry. */\n readonly object: TileMapObject;\n}\n\n/**\n * Build the {@link MapObjectDescriptor} for one object of `layer`.\n *\n * Exposed for code that spawns from a hand-picked object rather than from a\n * whole map; {@link mapObjectDescriptors} covers the common case.\n */\nexport const mapObjectDescriptor = (object: TileMapObject, layer: ObjectLayer): MapObjectDescriptor => ({\n id: object.sourceId ?? String(object.id),\n kind: object.type === '' ? null : object.type,\n name: object.name,\n x: object.x,\n y: object.y,\n width: object.width,\n height: object.height,\n rotation: object.rotation,\n properties: object.properties,\n layer,\n object,\n});\n\n/**\n * Every object of `map`, in a defined order: object-layer order first, then\n * object order within each layer.\n *\n * This is the order a {@link import('./MapObjectSpawner').MapObjectSpawner}\n * spawns in, so the same map always produces the same sequence.\n */\nexport const mapObjectDescriptors = function* (map: TileMap): Generator<MapObjectDescriptor> {\n for (const layer of map.objectLayers) {\n for (const object of layer.objects) {\n yield mapObjectDescriptor(object, layer);\n }\n }\n};\n"],"mappings":";;;;;;;AA8DA,MAAa,uBAAuB,QAAuB,WAA6C;CACtG,IAAI,OAAO,YAAY,OAAO,OAAO,EAAE;CACvC,MAAM,OAAO,SAAS,KAAK,OAAO,OAAO;CACzC,MAAM,OAAO;CACb,GAAG,OAAO;CACV,GAAG,OAAO;CACV,OAAO,OAAO;CACd,QAAQ,OAAO;CACf,UAAU,OAAO;CACjB,YAAY,OAAO;CACnB;CACA;AACF;;;;;;;;AASA,MAAa,uBAAuB,WAAW,KAA8C;CAC3F,KAAK,MAAM,SAAS,IAAI,cACtB,KAAK,MAAM,UAAU,MAAM,SACzB,MAAM,oBAAoB,QAAQ,KAAK;AAG7C"}