@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,81 +1,73 @@
1
+ //#region src/WangSet.ts
1
2
  /**
2
- * Describes a Wang autotile set: a mapping from a neighbor bitmask to a
3
- * local tile ID within a specific tileset.
4
- *
5
- * Blob bitmask bit layout (powers of 2):
6
- * - Bit 0 (1): Top-left
7
- * - Bit 1 (2): Top
8
- * - Bit 2 (4): Top-right
9
- * - Bit 3 (8): Left
10
- * - Bit 4 (16): Right
11
- * - Bit 5 (32): Bottom-left
12
- * - Bit 6 (64): Bottom
13
- * - Bit 7 (128): Bottom-right
14
- *
15
- * Diagonal (corner) bits are only set when both adjacent cardinal directions
16
- * are also set reducing 256 raw combinations to 47 meaningful blob states.
17
- *
18
- * Edge bitmask bit layout:
19
- * - Bit 0 (1): Top
20
- * - Bit 1 (2): Right
21
- * - Bit 2 (4): Bottom
22
- * - Bit 3 (8): Left
23
- */
24
- class WangSet {
25
- /** Index of the tileset that contains the Wang tiles. */
26
- tilesetIndex;
27
- /** The Wang mode: `'blob'` (8-neighbor) or `'edge'` (4-neighbor). */
28
- type;
29
- _map;
30
- _members;
31
- constructor(options) {
32
- this.tilesetIndex = options.tilesetIndex;
33
- this.type = options.type ?? 'blob';
34
- if (options.blobMap instanceof Map) {
35
- this._map = options.blobMap;
36
- }
37
- else {
38
- const map = new Map();
39
- for (const [k, v] of Object.entries(options.blobMap)) {
40
- map.set(Number(k), v);
41
- }
42
- this._map = map;
43
- }
44
- // Members default to every variant tile ID the set can produce, so that any
45
- // autotiled variant is recognised as part of the group (variant-stable
46
- // membership). Explicit `members` (e.g. the base paint ID) are added on top.
47
- const members = new Set(this._map.values());
48
- if (options.members) {
49
- for (const id of options.members)
50
- members.add(id);
51
- }
52
- this._members = members;
53
- }
54
- /**
55
- * Look up the local tile ID for a given neighbor bitmask.
56
- * Returns `undefined` if the mask has no mapping in this set.
57
- */
58
- getTileId(mask) {
59
- return this._map.get(mask);
60
- }
61
- /**
62
- * Whether a local tile ID belongs to this Wang group. True for every variant
63
- * the set produces plus any explicit {@link WangSetOptions.members}. Used as
64
- * the default, variant-stable neighbour-membership test by {@link autoTile}
65
- * and `refreshCell`.
66
- */
67
- isMember(localTileId) {
68
- return this._members.has(localTileId);
69
- }
70
- /** Read-only view of the full bitmask → tile-ID mapping. */
71
- get blobMap() {
72
- return this._map;
73
- }
74
- /** Read-only view of the local tile IDs that count as group members. */
75
- get members() {
76
- return this._members;
77
- }
78
- }
3
+ * Describes a Wang autotile set: a mapping from a neighbor bitmask to a
4
+ * local tile ID within a specific tileset.
5
+ *
6
+ * Blob bitmask bit layout (powers of 2):
7
+ * - Bit 0 (1): Top-left
8
+ * - Bit 1 (2): Top
9
+ * - Bit 2 (4): Top-right
10
+ * - Bit 3 (8): Left
11
+ * - Bit 4 (16): Right
12
+ * - Bit 5 (32): Bottom-left
13
+ * - Bit 6 (64): Bottom
14
+ * - Bit 7 (128): Bottom-right
15
+ *
16
+ * Diagonal (corner) bits are only set when both adjacent cardinal directions
17
+ * are also set - reducing 256 raw combinations to 47 meaningful blob states.
18
+ *
19
+ * Edge bitmask bit layout:
20
+ * - Bit 0 (1): Top
21
+ * - Bit 1 (2): Right
22
+ * - Bit 2 (4): Bottom
23
+ * - Bit 3 (8): Left
24
+ */
25
+ var WangSet = class {
26
+ /** Index of the tileset that contains the Wang tiles. */
27
+ tilesetIndex;
28
+ /** The Wang mode: `'blob'` (8-neighbor) or `'edge'` (4-neighbor). */
29
+ type;
30
+ _map;
31
+ _members;
32
+ constructor(options) {
33
+ this.tilesetIndex = options.tilesetIndex;
34
+ this.type = options.type ?? "blob";
35
+ if (options.blobMap instanceof Map) this._map = options.blobMap;
36
+ else {
37
+ const map = /* @__PURE__ */ new Map();
38
+ for (const [k, v] of Object.entries(options.blobMap)) map.set(Number(k), v);
39
+ this._map = map;
40
+ }
41
+ const members = new Set(this._map.values());
42
+ if (options.members) for (const id of options.members) members.add(id);
43
+ this._members = members;
44
+ }
45
+ /**
46
+ * Look up the local tile ID for a given neighbor bitmask.
47
+ * Returns `undefined` if the mask has no mapping in this set.
48
+ */
49
+ getTileId(mask) {
50
+ return this._map.get(mask);
51
+ }
52
+ /**
53
+ * Whether a local tile ID belongs to this Wang group. True for every variant
54
+ * the set produces plus any explicit {@link WangSetOptions.members}. Used as
55
+ * the default, variant-stable neighbour-membership test by {@link autoTile}
56
+ * and `refreshCell`.
57
+ */
58
+ isMember(localTileId) {
59
+ return this._members.has(localTileId);
60
+ }
61
+ /** Read-only view of the full bitmask → tile-ID mapping. */
62
+ get blobMap() {
63
+ return this._map;
64
+ }
65
+ /** Read-only view of the local tile IDs that count as group members. */
66
+ get members() {
67
+ return this._members;
68
+ }
69
+ };
79
70
 
71
+ //#endregion
80
72
  export { WangSet };
81
- //# sourceMappingURL=WangSet.js.map
73
+ //# sourceMappingURL=WangSet.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WangSet.js","sources":["../../../src/WangSet.ts"],"sourcesContent":[null],"names":[],"mappings":"AAgCA;;;;;;;;;;;;;;;;;;;;;;AAsBG;MACU,OAAO,CAAA;;AAEF,IAAA,YAAY;;AAGZ,IAAA,IAAI;AAEH,IAAA,IAAI;AACJ,IAAA,QAAQ;AAEzB,IAAA,WAAA,CAAmB,OAAuB,EAAA;AACxC,QAAA,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY;QACxC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,MAAM;AAElC,QAAA,IAAI,OAAO,CAAC,OAAO,YAAY,GAAG,EAAE;AAClC,YAAA,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO;QAC7B;aAAO;AACL,YAAA,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB;AACrC,YAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAiC,CAAC,EAAE;gBAC9E,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACvB;AACA,YAAA,IAAI,CAAC,IAAI,GAAG,GAAG;QACjB;;;;AAKA,QAAA,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;AACnD,QAAA,IAAI,OAAO,CAAC,OAAO,EAAE;AACnB,YAAA,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,OAAO;AAAE,gBAAA,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD;AACA,QAAA,IAAI,CAAC,QAAQ,GAAG,OAAO;IACzB;AAEA;;;AAGG;AACI,IAAA,SAAS,CAAC,IAAY,EAAA;QAC3B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;IAC5B;AAEA;;;;;AAKG;AACI,IAAA,QAAQ,CAAC,WAAmB,EAAA;QACjC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC;IACvC;;AAGA,IAAA,IAAW,OAAO,GAAA;QAChB,OAAO,IAAI,CAAC,IAAI;IAClB;;AAGA,IAAA,IAAW,OAAO,GAAA;QAChB,OAAO,IAAI,CAAC,QAAQ;IACtB;AACD;;;;"}
1
+ {"version":3,"file":"WangSet.js","names":[],"sources":["../../src/WangSet.ts"],"sourcesContent":["/**\n * Options for constructing a {@link WangSet}.\n */\nexport interface WangSetOptions {\n /** Which TileSet contains the Wang tiles (index into the layer's tilesets array). */\n tilesetIndex: number;\n /**\n * Map from Wang bitmask to local tile ID within the tileset.\n *\n * For blob mode (8-neighbor), keys are 0-255; the 47 valid combinations\n * of the blob encoding must be covered at minimum.\n * For edge mode (4-neighbor), keys are 0-15.\n *\n * Accepts either a {@link ReadonlyMap} or a plain `Record<number, number>`.\n */\n blobMap: ReadonlyMap<number, number> | Record<number, number>;\n /** Whether this is a blob (8-neighbor, default) or edge (4-neighbor) Wang set. */\n type?: 'blob' | 'edge';\n /**\n * Extra local tile IDs that count as belonging to this Wang group, beyond\n * the variant IDs already present as {@link blobMap} *values*.\n *\n * Membership is what {@link autoTile} / `refreshCell` use to decide whether a\n * neighbouring cell is \"part of the terrain\". Because every value in\n * `blobMap` is itself a member, group membership stays stable no matter which\n * variant a cell currently shows - that is what makes incremental\n * `refreshCell` correct. Add the *base* tile ID you paint with here if it is\n * not already one of the blobMap variants.\n */\n members?: Iterable<number>;\n}\n\n/**\n * Describes a Wang autotile set: a mapping from a neighbor bitmask to a\n * local tile ID within a specific tileset.\n *\n * Blob bitmask bit layout (powers of 2):\n * - Bit 0 (1): Top-left\n * - Bit 1 (2): Top\n * - Bit 2 (4): Top-right\n * - Bit 3 (8): Left\n * - Bit 4 (16): Right\n * - Bit 5 (32): Bottom-left\n * - Bit 6 (64): Bottom\n * - Bit 7 (128): Bottom-right\n *\n * Diagonal (corner) bits are only set when both adjacent cardinal directions\n * are also set - reducing 256 raw combinations to 47 meaningful blob states.\n *\n * Edge bitmask bit layout:\n * - Bit 0 (1): Top\n * - Bit 1 (2): Right\n * - Bit 2 (4): Bottom\n * - Bit 3 (8): Left\n */\nexport class WangSet {\n /** Index of the tileset that contains the Wang tiles. */\n public readonly tilesetIndex: number;\n\n /** The Wang mode: `'blob'` (8-neighbor) or `'edge'` (4-neighbor). */\n public readonly type: 'blob' | 'edge';\n\n private readonly _map: ReadonlyMap<number, number>;\n private readonly _members: ReadonlySet<number>;\n\n public constructor(options: WangSetOptions) {\n this.tilesetIndex = options.tilesetIndex;\n this.type = options.type ?? 'blob';\n\n if (options.blobMap instanceof Map) {\n this._map = options.blobMap;\n } else {\n const map = new Map<number, number>();\n for (const [k, v] of Object.entries(options.blobMap as Record<string, number>)) {\n map.set(Number(k), v);\n }\n this._map = map;\n }\n\n // Members default to every variant tile ID the set can produce, so that any\n // autotiled variant is recognised as part of the group (variant-stable\n // membership). Explicit `members` (e.g. the base paint ID) are added on top.\n const members = new Set<number>(this._map.values());\n if (options.members) {\n for (const id of options.members) members.add(id);\n }\n this._members = members;\n }\n\n /**\n * Look up the local tile ID for a given neighbor bitmask.\n * Returns `undefined` if the mask has no mapping in this set.\n */\n public getTileId(mask: number): number | undefined {\n return this._map.get(mask);\n }\n\n /**\n * Whether a local tile ID belongs to this Wang group. True for every variant\n * the set produces plus any explicit {@link WangSetOptions.members}. Used as\n * the default, variant-stable neighbour-membership test by {@link autoTile}\n * and `refreshCell`.\n */\n public isMember(localTileId: number): boolean {\n return this._members.has(localTileId);\n }\n\n /** Read-only view of the full bitmask → tile-ID mapping. */\n public get blobMap(): ReadonlyMap<number, number> {\n return this._map;\n }\n\n /** Read-only view of the local tile IDs that count as group members. */\n public get members(): ReadonlySet<number> {\n return this._members;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAuDA,IAAa,UAAb,MAAqB;;CAEnB,AAAgB;;CAGhB,AAAgB;CAEhB,AAAiB;CACjB,AAAiB;CAEjB,AAAO,YAAY,SAAyB;EAC1C,KAAK,eAAe,QAAQ;EAC5B,KAAK,OAAO,QAAQ,QAAQ;EAE5B,IAAI,QAAQ,mBAAmB,KAC7B,KAAK,OAAO,QAAQ;OACf;GACL,MAAM,sBAAM,IAAI,IAAoB;GACpC,KAAK,MAAM,CAAC,GAAG,MAAM,OAAO,QAAQ,QAAQ,OAAiC,GAC3E,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC;GAEtB,KAAK,OAAO;EACd;EAKA,MAAM,UAAU,IAAI,IAAY,KAAK,KAAK,OAAO,CAAC;EAClD,IAAI,QAAQ,SACV,KAAK,MAAM,MAAM,QAAQ,SAAS,QAAQ,IAAI,EAAE;EAElD,KAAK,WAAW;CAClB;;;;;CAMA,AAAO,UAAU,MAAkC;EACjD,OAAO,KAAK,KAAK,IAAI,IAAI;CAC3B;;;;;;;CAQA,AAAO,SAAS,aAA8B;EAC5C,OAAO,KAAK,SAAS,IAAI,WAAW;CACtC;;CAGA,IAAW,UAAuC;EAChD,OAAO,KAAK;CACd;;CAGA,IAAW,UAA+B;EACxC,OAAO,KAAK;CACd;AACF"}
@@ -0,0 +1,95 @@
1
+ import type { ChunkSource } from './ChunkSource';
2
+ import type { TileLayer } from './TileLayer';
3
+ import type { ResolvedTile } from './types';
4
+ /**
5
+ * Options for {@link createWorkerSampledChunkSource}.
6
+ * @advanced
7
+ */
8
+ export interface WorkerSampledChunkSourceOptions {
9
+ /**
10
+ * Complete worker script source as a single self-contained string, Blob-URL'd
11
+ * into a real `Worker` at construction time - the same technique
12
+ * {@link import('@codexo/exojs').WorkletEffect} uses for AudioWorklet
13
+ * processors. No separate worker asset is fetched and no bundler-specific
14
+ * worker-import syntax is involved.
15
+ *
16
+ * Producing that string by hand-writing JavaScript into a template literal
17
+ * works but gives up type checking, linting and shared code. Prefer a build
18
+ * step that bundles a real module into a string: this repository's own
19
+ * examples are authored as `*.worker.ts` and imported through a `?worker`
20
+ * query, which is why they can `import` the sampling functions the main
21
+ * thread uses instead of restating them.
22
+ *
23
+ * Must implement this request/response protocol:
24
+ * - Request (received via `self.onmessage`):
25
+ * `{ requestId: number; cx: number; cy: number; chunkWidth: number; chunkHeight: number }`.
26
+ * - Response, success (send via `self.postMessage`, transferring the
27
+ * buffer for a zero-copy handoff - `postMessage(response, [response.values.buffer])`):
28
+ * `{ requestId: number; values: Float64Array }`, `values.length ===
29
+ * chunkWidth * chunkHeight`, row-major (`localTy * chunkWidth + localTx`),
30
+ * one sampled value per tile in the requested chunk. Compute each tile's
31
+ * absolute coordinate as `cx * chunkWidth + localTx` /
32
+ * `cy * chunkHeight + localTy`.
33
+ * - Response, error (one request failed without crashing the worker):
34
+ * `{ requestId: number; error: string }`.
35
+ *
36
+ * Your worker must reply to every request with exactly one success or
37
+ * error message bearing the same `requestId`. A request left unanswered
38
+ * leaves that chunk permanently unfetched - there is no timeout - since
39
+ * `ChunkStreamer` tracks it as still in flight and never retries it.
40
+ */
41
+ workerSource: string;
42
+ /**
43
+ * Posted to the worker once, before any chunk request, when present.
44
+ *
45
+ * The transport for whatever the sampler needs to know that is not per-chunk
46
+ * - a seed, a feature size, a cost knob. Without it those values would have
47
+ * to be interpolated into {@link WorkerSampledChunkSourceOptions.workerSource}
48
+ * as literals, which turns every parameter change into a source rebuild and a
49
+ * new `Worker`.
50
+ *
51
+ * `postMessage` delivery is ordered, so the worker is guaranteed to see this
52
+ * before the first request. Distinguish it from a chunk request by its own
53
+ * shape; requests carry a `requestId`.
54
+ */
55
+ initMessage?: unknown;
56
+ /**
57
+ * Convert a sampled value (and its absolute tile coordinate) into a
58
+ * resolved tile, or `null` for an empty cell. Always runs on the main
59
+ * thread - a `ResolvedTile` references a `TileSet`/`Texture`, neither of
60
+ * which can cross a `postMessage` boundary. Must be pure and
61
+ * deterministic, same requirement as
62
+ * {@link import('./SampledChunkSource').SampledChunkSourceOptions.mapValueToTile}.
63
+ */
64
+ mapValueToTile(value: number, tx: number, ty: number): ResolvedTile | null;
65
+ }
66
+ /**
67
+ * Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready
68
+ * {@link ChunkSource} that samples off the main thread via a Web Worker -
69
+ * the async counterpart to
70
+ * {@link import('./SampledChunkSource').createSampledChunkSource}, for
71
+ * sampling functions expensive enough to want off-thread execution.
72
+ *
73
+ * Unlike the synchronous provider, sampling logic cannot be passed as a
74
+ * live function - functions cannot cross a `postMessage` boundary. Instead
75
+ * {@link WorkerSampledChunkSourceOptions.workerSource} is a self-contained
76
+ * worker script string; see its documentation for the protocol.
77
+ *
78
+ * The returned value's `destroy()` MUST be called when done with it (e.g.
79
+ * alongside your `ChunkStreamer.destroy()` call) - the underlying `Worker`
80
+ * is a real resource that leaks otherwise. `ChunkSource` itself has no
81
+ * lifecycle hook, so this is not automatic.
82
+ *
83
+ * Implementation note: `workerSource` is Blob-URL'd into a real `Worker`
84
+ * (`new Blob([workerSource])` → `URL.createObjectURL` → `new Worker(url)`) -
85
+ * the same technique {@link import('@codexo/exojs').WorkletEffect} already
86
+ * uses for AudioWorklet processors. This is bundler-agnostic (no special
87
+ * config needed in Vite/webpack/etc.) but requires a Content-Security-Policy
88
+ * that permits `blob:` in `worker-src` (or `script-src` as a fallback) if
89
+ * your deployment sets one.
90
+ * @advanced
91
+ */
92
+ export declare const createWorkerSampledChunkSource: (layer: TileLayer, options: WorkerSampledChunkSourceOptions) => ChunkSource & {
93
+ destroy(): void;
94
+ };
95
+ //# sourceMappingURL=WorkerSampledChunkSource.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerSampledChunkSource.d.ts","sourceRoot":"","sources":["../../src/WorkerSampledChunkSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C;;;GAGG;AACH,MAAM,WAAW,+BAA+B;IAC9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;;;;OAOG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;CAC5E;AAiCD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,8BAA8B,GAAI,OAAO,SAAS,EAAE,SAAS,+BAA+B,KAAG,WAAW,GAAG;IAAE,OAAO,IAAI,IAAI,CAAA;CA8F1I,CAAC"}
@@ -0,0 +1,117 @@
1
+ import { packTile } from "./types.js";
2
+
3
+ //#region src/WorkerSampledChunkSource.ts
4
+ const isWorkerErrorMessage = (message) => "error" in message;
5
+ /**
6
+ * Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready
7
+ * {@link ChunkSource} that samples off the main thread via a Web Worker -
8
+ * the async counterpart to
9
+ * {@link import('./SampledChunkSource').createSampledChunkSource}, for
10
+ * sampling functions expensive enough to want off-thread execution.
11
+ *
12
+ * Unlike the synchronous provider, sampling logic cannot be passed as a
13
+ * live function - functions cannot cross a `postMessage` boundary. Instead
14
+ * {@link WorkerSampledChunkSourceOptions.workerSource} is a self-contained
15
+ * worker script string; see its documentation for the protocol.
16
+ *
17
+ * The returned value's `destroy()` MUST be called when done with it (e.g.
18
+ * alongside your `ChunkStreamer.destroy()` call) - the underlying `Worker`
19
+ * is a real resource that leaks otherwise. `ChunkSource` itself has no
20
+ * lifecycle hook, so this is not automatic.
21
+ *
22
+ * Implementation note: `workerSource` is Blob-URL'd into a real `Worker`
23
+ * (`new Blob([workerSource])` → `URL.createObjectURL` → `new Worker(url)`) -
24
+ * the same technique {@link import('@codexo/exojs').WorkletEffect} already
25
+ * uses for AudioWorklet processors. This is bundler-agnostic (no special
26
+ * config needed in Vite/webpack/etc.) but requires a Content-Security-Policy
27
+ * that permits `blob:` in `worker-src` (or `script-src` as a fallback) if
28
+ * your deployment sets one.
29
+ * @advanced
30
+ */
31
+ const createWorkerSampledChunkSource = (layer, options) => {
32
+ const mapValueToTile = options.mapValueToTile.bind(options);
33
+ const blob = new Blob([options.workerSource], { type: "application/javascript" });
34
+ const url = URL.createObjectURL(blob);
35
+ const worker = new Worker(url);
36
+ URL.revokeObjectURL(url);
37
+ if (options.initMessage !== void 0) worker.postMessage(options.initMessage);
38
+ let requestCounter = 0;
39
+ const pending = /* @__PURE__ */ new Map();
40
+ let destroyed = false;
41
+ const composePayload = (values, request) => {
42
+ const { cx, cy, chunkWidth, chunkHeight } = request;
43
+ const startTx = cx * chunkWidth;
44
+ const startTy = cy * chunkHeight;
45
+ let out = null;
46
+ for (let ty = startTy; ty < startTy + chunkHeight; ty++) for (let tx = startTx; tx < startTx + chunkWidth; tx++) {
47
+ if (layer.width !== void 0 && layer.height !== void 0 && (tx >= layer.width || ty >= layer.height)) continue;
48
+ const localIndex = (ty - startTy) * chunkWidth + (tx - startTx);
49
+ const value = values[localIndex];
50
+ if (value === void 0) continue;
51
+ const resolved = mapValueToTile(value, tx, ty);
52
+ if (!resolved) continue;
53
+ out ??= new Uint32Array(chunkWidth * chunkHeight);
54
+ const tilesetIndex = layer.tilesets.indexOf(resolved.tileset);
55
+ out[localIndex] = packTile(tilesetIndex, resolved.localTileId, resolved.transform);
56
+ }
57
+ return out === null ? null : {
58
+ width: chunkWidth,
59
+ height: chunkHeight,
60
+ tiles: out
61
+ };
62
+ };
63
+ worker.onmessage = (event) => {
64
+ const message = event.data;
65
+ const entry = pending.get(message.requestId);
66
+ if (!entry) return;
67
+ pending.delete(message.requestId);
68
+ if (isWorkerErrorMessage(message)) {
69
+ entry.reject(new Error(message.error));
70
+ return;
71
+ }
72
+ entry.resolve(composePayload(message.values, entry));
73
+ };
74
+ worker.onerror = (event) => {
75
+ const error = /* @__PURE__ */ new Error(`WorkerSampledChunkSource worker error: ${event.message}`);
76
+ for (const entry of pending.values()) entry.reject(error);
77
+ pending.clear();
78
+ };
79
+ return {
80
+ getChunk(cx, cy) {
81
+ if (destroyed) return Promise.reject(/* @__PURE__ */ new Error("WorkerSampledChunkSource: getChunk() called after destroy()."));
82
+ const chunkWidth = layer.chunkWidth;
83
+ const chunkHeight = layer.chunkHeight;
84
+ const requestId = ++requestCounter;
85
+ return new Promise((resolve, reject) => {
86
+ pending.set(requestId, {
87
+ resolve,
88
+ reject,
89
+ cx,
90
+ cy,
91
+ chunkWidth,
92
+ chunkHeight
93
+ });
94
+ const request = {
95
+ requestId,
96
+ cx,
97
+ cy,
98
+ chunkWidth,
99
+ chunkHeight
100
+ };
101
+ worker.postMessage(request);
102
+ });
103
+ },
104
+ destroy() {
105
+ if (destroyed) return;
106
+ destroyed = true;
107
+ const error = /* @__PURE__ */ new Error("WorkerSampledChunkSource destroyed.");
108
+ for (const entry of pending.values()) entry.reject(error);
109
+ pending.clear();
110
+ worker.terminate();
111
+ }
112
+ };
113
+ };
114
+
115
+ //#endregion
116
+ export { createWorkerSampledChunkSource };
117
+ //# sourceMappingURL=WorkerSampledChunkSource.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WorkerSampledChunkSource.js","names":[],"sources":["../../src/WorkerSampledChunkSource.ts"],"sourcesContent":["import type { ChunkPayload, ChunkSource } from './ChunkSource';\nimport type { TileLayer } from './TileLayer';\nimport type { ResolvedTile } from './types';\nimport { packTile } from './types';\n\n/**\n * Options for {@link createWorkerSampledChunkSource}.\n * @advanced\n */\nexport interface WorkerSampledChunkSourceOptions {\n /**\n * Complete worker script source as a single self-contained string, Blob-URL'd\n * into a real `Worker` at construction time - the same technique\n * {@link import('@codexo/exojs').WorkletEffect} uses for AudioWorklet\n * processors. No separate worker asset is fetched and no bundler-specific\n * worker-import syntax is involved.\n *\n * Producing that string by hand-writing JavaScript into a template literal\n * works but gives up type checking, linting and shared code. Prefer a build\n * step that bundles a real module into a string: this repository's own\n * examples are authored as `*.worker.ts` and imported through a `?worker`\n * query, which is why they can `import` the sampling functions the main\n * thread uses instead of restating them.\n *\n * Must implement this request/response protocol:\n * - Request (received via `self.onmessage`):\n * `{ requestId: number; cx: number; cy: number; chunkWidth: number; chunkHeight: number }`.\n * - Response, success (send via `self.postMessage`, transferring the\n * buffer for a zero-copy handoff - `postMessage(response, [response.values.buffer])`):\n * `{ requestId: number; values: Float64Array }`, `values.length ===\n * chunkWidth * chunkHeight`, row-major (`localTy * chunkWidth + localTx`),\n * one sampled value per tile in the requested chunk. Compute each tile's\n * absolute coordinate as `cx * chunkWidth + localTx` /\n * `cy * chunkHeight + localTy`.\n * - Response, error (one request failed without crashing the worker):\n * `{ requestId: number; error: string }`.\n *\n * Your worker must reply to every request with exactly one success or\n * error message bearing the same `requestId`. A request left unanswered\n * leaves that chunk permanently unfetched - there is no timeout - since\n * `ChunkStreamer` tracks it as still in flight and never retries it.\n */\n workerSource: string;\n /**\n * Posted to the worker once, before any chunk request, when present.\n *\n * The transport for whatever the sampler needs to know that is not per-chunk\n * - a seed, a feature size, a cost knob. Without it those values would have\n * to be interpolated into {@link WorkerSampledChunkSourceOptions.workerSource}\n * as literals, which turns every parameter change into a source rebuild and a\n * new `Worker`.\n *\n * `postMessage` delivery is ordered, so the worker is guaranteed to see this\n * before the first request. Distinguish it from a chunk request by its own\n * shape; requests carry a `requestId`.\n */\n initMessage?: unknown;\n /**\n * Convert a sampled value (and its absolute tile coordinate) into a\n * resolved tile, or `null` for an empty cell. Always runs on the main\n * thread - a `ResolvedTile` references a `TileSet`/`Texture`, neither of\n * which can cross a `postMessage` boundary. Must be pure and\n * deterministic, same requirement as\n * {@link import('./SampledChunkSource').SampledChunkSourceOptions.mapValueToTile}.\n */\n mapValueToTile(value: number, tx: number, ty: number): ResolvedTile | null;\n}\n\ninterface WorkerRequestMessage {\n readonly requestId: number;\n readonly cx: number;\n readonly cy: number;\n readonly chunkWidth: number;\n readonly chunkHeight: number;\n}\n\ninterface WorkerSuccessMessage {\n readonly requestId: number;\n readonly values: Float64Array;\n}\n\ninterface WorkerErrorMessage {\n readonly requestId: number;\n readonly error: string;\n}\n\ntype WorkerResponseMessage = WorkerSuccessMessage | WorkerErrorMessage;\n\nconst isWorkerErrorMessage = (message: WorkerResponseMessage): message is WorkerErrorMessage => 'error' in message;\n\ninterface PendingRequest {\n readonly resolve: (payload: ChunkPayload | null) => void;\n readonly reject: (error: Error) => void;\n readonly cx: number;\n readonly cy: number;\n readonly chunkWidth: number;\n readonly chunkHeight: number;\n}\n\n/**\n * Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready\n * {@link ChunkSource} that samples off the main thread via a Web Worker -\n * the async counterpart to\n * {@link import('./SampledChunkSource').createSampledChunkSource}, for\n * sampling functions expensive enough to want off-thread execution.\n *\n * Unlike the synchronous provider, sampling logic cannot be passed as a\n * live function - functions cannot cross a `postMessage` boundary. Instead\n * {@link WorkerSampledChunkSourceOptions.workerSource} is a self-contained\n * worker script string; see its documentation for the protocol.\n *\n * The returned value's `destroy()` MUST be called when done with it (e.g.\n * alongside your `ChunkStreamer.destroy()` call) - the underlying `Worker`\n * is a real resource that leaks otherwise. `ChunkSource` itself has no\n * lifecycle hook, so this is not automatic.\n *\n * Implementation note: `workerSource` is Blob-URL'd into a real `Worker`\n * (`new Blob([workerSource])` → `URL.createObjectURL` → `new Worker(url)`) -\n * the same technique {@link import('@codexo/exojs').WorkletEffect} already\n * uses for AudioWorklet processors. This is bundler-agnostic (no special\n * config needed in Vite/webpack/etc.) but requires a Content-Security-Policy\n * that permits `blob:` in `worker-src` (or `script-src` as a fallback) if\n * your deployment sets one.\n * @advanced\n */\nexport const createWorkerSampledChunkSource = (layer: TileLayer, options: WorkerSampledChunkSourceOptions): ChunkSource & { destroy(): void } => {\n const mapValueToTile = options.mapValueToTile.bind(options);\n\n const blob = new Blob([options.workerSource], { type: 'application/javascript' });\n const url = URL.createObjectURL(blob);\n const worker = new Worker(url);\n URL.revokeObjectURL(url);\n\n if (options.initMessage !== undefined) {\n worker.postMessage(options.initMessage);\n }\n\n let requestCounter = 0;\n const pending = new Map<number, PendingRequest>();\n let destroyed = false;\n\n const composePayload = (values: Float64Array, request: PendingRequest): ChunkPayload | null => {\n const { cx, cy, chunkWidth, chunkHeight } = request;\n const startTx = cx * chunkWidth;\n const startTy = cy * chunkHeight;\n\n let out: Uint32Array | null = null;\n for (let ty = startTy; ty < startTy + chunkHeight; ty++) {\n for (let tx = startTx; tx < startTx + chunkWidth; tx++) {\n // Bounded-layer edge chunks may be smaller than a full chunk - same\n // clamp createSampledChunkSource applies, computed here (not asked\n // of the worker) since only this side knows the layer's bounds.\n if (layer.width !== undefined && layer.height !== undefined && (tx >= layer.width || ty >= layer.height)) continue;\n\n const localIndex = (ty - startTy) * chunkWidth + (tx - startTx);\n const value = values[localIndex];\n if (value === undefined) continue; // defensive: malformed/short values array\n const resolved = mapValueToTile(value, tx, ty);\n if (!resolved) continue;\n\n out ??= new Uint32Array(chunkWidth * chunkHeight);\n const tilesetIndex = layer.tilesets.indexOf(resolved.tileset);\n out[localIndex] = packTile(tilesetIndex, resolved.localTileId, resolved.transform);\n }\n }\n\n return out === null ? null : { width: chunkWidth, height: chunkHeight, tiles: out };\n };\n\n worker.onmessage = (event: MessageEvent<WorkerResponseMessage>): void => {\n const message = event.data;\n const entry = pending.get(message.requestId);\n if (!entry) return; // stale/unknown requestId (e.g. arrived after destroy())\n pending.delete(message.requestId);\n\n if (isWorkerErrorMessage(message)) {\n entry.reject(new Error(message.error));\n return;\n }\n\n entry.resolve(composePayload(message.values, entry));\n };\n\n worker.onerror = (event: ErrorEvent): void => {\n const error = new Error(`WorkerSampledChunkSource worker error: ${event.message}`);\n for (const entry of pending.values()) {\n entry.reject(error);\n }\n pending.clear();\n };\n\n return {\n getChunk(cx: number, cy: number): Promise<ChunkPayload | null> {\n if (destroyed) {\n return Promise.reject(new Error('WorkerSampledChunkSource: getChunk() called after destroy().'));\n }\n\n const chunkWidth = layer.chunkWidth;\n const chunkHeight = layer.chunkHeight;\n const requestId = ++requestCounter;\n\n return new Promise<ChunkPayload | null>((resolve, reject) => {\n pending.set(requestId, { resolve, reject, cx, cy, chunkWidth, chunkHeight });\n const request: WorkerRequestMessage = { requestId, cx, cy, chunkWidth, chunkHeight };\n worker.postMessage(request);\n });\n },\n\n destroy(): void {\n if (destroyed) return;\n destroyed = true;\n const error = new Error('WorkerSampledChunkSource destroyed.');\n for (const entry of pending.values()) {\n entry.reject(error);\n }\n pending.clear();\n worker.terminate();\n },\n };\n};\n"],"mappings":";;;AAwFA,MAAM,wBAAwB,YAAkE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqC3G,MAAa,kCAAkC,OAAkB,YAAgF;CAC/I,MAAM,iBAAiB,QAAQ,eAAe,KAAK,OAAO;CAE1D,MAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,YAAY,GAAG,EAAE,MAAM,yBAAyB,CAAC;CAChF,MAAM,MAAM,IAAI,gBAAgB,IAAI;CACpC,MAAM,SAAS,IAAI,OAAO,GAAG;CAC7B,IAAI,gBAAgB,GAAG;CAEvB,IAAI,QAAQ,gBAAgB,QAC1B,OAAO,YAAY,QAAQ,WAAW;CAGxC,IAAI,iBAAiB;CACrB,MAAM,0BAAU,IAAI,IAA4B;CAChD,IAAI,YAAY;CAEhB,MAAM,kBAAkB,QAAsB,YAAiD;EAC7F,MAAM,EAAE,IAAI,IAAI,YAAY,gBAAgB;EAC5C,MAAM,UAAU,KAAK;EACrB,MAAM,UAAU,KAAK;EAErB,IAAI,MAA0B;EAC9B,KAAK,IAAI,KAAK,SAAS,KAAK,UAAU,aAAa,MACjD,KAAK,IAAI,KAAK,SAAS,KAAK,UAAU,YAAY,MAAM;GAItD,IAAI,MAAM,UAAU,UAAa,MAAM,WAAW,WAAc,MAAM,MAAM,SAAS,MAAM,MAAM,SAAS;GAE1G,MAAM,cAAc,KAAK,WAAW,cAAc,KAAK;GACvD,MAAM,QAAQ,OAAO;GACrB,IAAI,UAAU,QAAW;GACzB,MAAM,WAAW,eAAe,OAAO,IAAI,EAAE;GAC7C,IAAI,CAAC,UAAU;GAEf,QAAQ,IAAI,YAAY,aAAa,WAAW;GAChD,MAAM,eAAe,MAAM,SAAS,QAAQ,SAAS,OAAO;GAC5D,IAAI,cAAc,SAAS,cAAc,SAAS,aAAa,SAAS,SAAS;EACnF;EAGF,OAAO,QAAQ,OAAO,OAAO;GAAE,OAAO;GAAY,QAAQ;GAAa,OAAO;EAAI;CACpF;CAEA,OAAO,aAAa,UAAqD;EACvE,MAAM,UAAU,MAAM;EACtB,MAAM,QAAQ,QAAQ,IAAI,QAAQ,SAAS;EAC3C,IAAI,CAAC,OAAO;EACZ,QAAQ,OAAO,QAAQ,SAAS;EAEhC,IAAI,qBAAqB,OAAO,GAAG;GACjC,MAAM,OAAO,IAAI,MAAM,QAAQ,KAAK,CAAC;GACrC;EACF;EAEA,MAAM,QAAQ,eAAe,QAAQ,QAAQ,KAAK,CAAC;CACrD;CAEA,OAAO,WAAW,UAA4B;EAC5C,MAAM,wBAAQ,IAAI,MAAM,0CAA0C,MAAM,SAAS;EACjF,KAAK,MAAM,SAAS,QAAQ,OAAO,GACjC,MAAM,OAAO,KAAK;EAEpB,QAAQ,MAAM;CAChB;CAEA,OAAO;EACL,SAAS,IAAY,IAA0C;GAC7D,IAAI,WACF,OAAO,QAAQ,uBAAO,IAAI,MAAM,8DAA8D,CAAC;GAGjG,MAAM,aAAa,MAAM;GACzB,MAAM,cAAc,MAAM;GAC1B,MAAM,YAAY,EAAE;GAEpB,OAAO,IAAI,SAA8B,SAAS,WAAW;IAC3D,QAAQ,IAAI,WAAW;KAAE;KAAS;KAAQ;KAAI;KAAI;KAAY;IAAY,CAAC;IAC3E,MAAM,UAAgC;KAAE;KAAW;KAAI;KAAI;KAAY;IAAY;IACnF,OAAO,YAAY,OAAO;GAC5B,CAAC;EACH;EAEA,UAAgB;GACd,IAAI,WAAW;GACf,YAAY;GACZ,MAAM,wBAAQ,IAAI,MAAM,qCAAqC;GAC7D,KAAK,MAAM,SAAS,QAAQ,OAAO,GACjC,MAAM,OAAO,KAAK;GAEpB,QAAQ,MAAM;GACd,OAAO,UAAU;EACnB;CACF;AACF"}
@@ -11,7 +11,7 @@ export interface AutoTileOptions {
11
11
  *
12
12
  * If omitted, group membership defaults to {@link WangSet.isMember} on the
13
13
  * cell's `localTileId` (and a matching `tilesetIndex`). That default is
14
- * *variant-stable* every autotiled variant counts as a member which is
14
+ * *variant-stable* - every autotiled variant counts as a member - which is
15
15
  * what makes {@link refreshCell} correct. If you supply a `matchFn` for use
16
16
  * with `refreshCell`, it MUST likewise be variant-stable (independent of the
17
17
  * currently-rendered variant), e.g. keyed on a separate logical-terrain grid
@@ -54,16 +54,20 @@ export interface AutoTileOptions {
54
54
  * combinations to 47 valid blob states).
55
55
  *
56
56
  * **Edge mode bitmask (bit positions):** Top=1, Right=2, Bottom=4, Left=8.
57
+ *
58
+ * @throws If `layer` is unbounded (no fixed width/height) - there is no
59
+ * "whole layer" to sweep. Use {@link refreshCell} to autotile an unbounded
60
+ * layer incrementally, one edited cell at a time.
57
61
  */
58
- export declare function autoTile(layer: TileLayer, wangSet: WangSet, options?: AutoTileOptions): void;
62
+ export declare const autoTile: (layer: TileLayer, wangSet: WangSet, options?: AutoTileOptions) => void;
59
63
  /**
60
64
  * Incrementally re-autotile a single cell and its eight neighbours after an
61
65
  * edit, instead of re-running {@link autoTile} over the whole layer.
62
66
  *
63
67
  * A cell's blob/edge mask depends only on its immediate neighbours, so painting
64
68
  * or erasing cell `(x, y)` can change the variant of that cell and of the (up
65
- * to) eight cells that have it as a neighbour but nothing further out. This
66
- * recomputes exactly that 3×3 neighbourhood, touching only the 14 chunks it
69
+ * to) eight cells that have it as a neighbour - but nothing further out. This
70
+ * recomputes exactly that 3×3 neighbourhood, touching only the 1-4 chunks it
67
71
  * spans (and rebuilding geometry only for chunks whose tiles actually change).
68
72
  * For a paint operation this is O(1) work versus `autoTile`'s O(width·height).
69
73
  *
@@ -80,4 +84,5 @@ export declare function autoTile(layer: TileLayer, wangSet: WangSet, options?: A
80
84
  * @param wangSet The Wang set to resolve variants from.
81
85
  * @param options Membership / border options (shared with {@link autoTile}).
82
86
  */
83
- export declare function refreshCell(layer: TileLayer, x: number, y: number, wangSet: WangSet, options?: AutoTileOptions): void;
87
+ export declare const refreshCell: (layer: TileLayer, x: number, y: number, wangSet: WangSet, options?: AutoTileOptions) => void;
88
+ //# sourceMappingURL=autoTile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"autoTile.d.ts","sourceRoot":"","sources":["../../src/autoTile.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IACvF;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA0ED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,SAAS,EAAE,SAAS,OAAO,EAAE,UAAU,eAAe,KAAG,IAuDxF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,WAAW,GAAI,OAAO,SAAS,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,SAAS,OAAO,EAAE,UAAU,eAAe,KAAG,IA0BjH,CAAC"}