@aethervtt/shard-sprite 0.0.1 → 0.2.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.
package/dist/tilemap.js CHANGED
@@ -8,20 +8,51 @@ import {
8
8
  } from "@aethervtt/shard-core";
9
9
  import { Visibility } from "@aethervtt/shard-render";
10
10
  import { Transform } from "@aethervtt/shard-transform";
11
+ import {
12
+ flagsFromBase64,
13
+ layerChunks,
14
+ readChunkRows,
15
+ rowsCanName,
16
+ tilesFromBase64,
17
+ tilesToBase64,
18
+ toBase64
19
+ } from "./tilemap-format.js";
11
20
  const TileFlags = { FlipX: 1, FlipY: 2, Rotate90: 4 };
12
21
  const TilemapDataSchema = defineSchema(
13
22
  "sprite/TilemapData",
14
23
  {
24
+ version: t.u8({
25
+ default: 1,
26
+ min: 1,
27
+ max: 2,
28
+ description: "2: tiles are named through the palette. 1 (old files): atlas region + 1."
29
+ }),
30
+ encoding: t.enum(["base64", "rows"], {
31
+ description: "rows: layers hold chunks of run-length rows (readable, one-line diffs). base64: tiles and flags as base64."
32
+ }),
33
+ chunkSize: t.u16({
34
+ default: 16,
35
+ min: 1,
36
+ max: 256,
37
+ description: "Tiles per chunk side in the rows encoding."
38
+ }),
39
+ palette: t.list(t.string, {
40
+ description: "Version 2: atlas region names; tile id N is palette entry N \u2212 1."
41
+ }),
15
42
  layers: t.list(
16
43
  t.struct({
17
44
  name: t.string({ description: 'Layer name, e.g. "ground".' }),
18
45
  width: t.u32({ min: 1, description: "Tiles across." }),
19
46
  height: t.u32({ min: 1, description: "Tiles down." }),
20
47
  tiles: t.string({
21
- description: "Base64 of width \xD7 height little-endian u16s, row by row from the top: atlas region + 1 (0 is empty)."
48
+ description: "base64 encoding: width \xD7 height little-endian u16s, row by row from the top: palette index + 1 (version 1: atlas region + 1); 0 is empty."
22
49
  }),
23
50
  flags: t.string({
24
- description: "Base64 of width \xD7 height bytes: 1 flip x, 2 flip y, 4 rotate 90\xB0. Empty: none."
51
+ description: "base64 encoding: width \xD7 height bytes: 1 flip x, 2 flip y, 4 rotate 90\xB0. Empty: none."
52
+ }),
53
+ chunks: t.json({
54
+ default: {},
55
+ description: 'rows encoding: "cx,cy" \u2192 rows from the top of the chunk, each space-separated runs of name[:fx+fy+r90][*count], "." empty. Chunks with no tiles are left out.'
25
56
  }),
26
57
  occludes: t.bool({
27
58
  description: "Filled cells block 2D light (shadowed PointLight2d and SpotLight2d)."
@@ -31,8 +62,10 @@ const TilemapDataSchema = defineSchema(
31
62
  ),
32
63
  animations: t.list(
33
64
  t.struct({
34
- tile: t.u16({ min: 1, description: "The tile that animates, everywhere it appears." }),
35
- frames: t.list(t.u16, { description: "Tiles it cycles through." }),
65
+ tile: t.json({
66
+ description: "The tile that animates, everywhere it appears: a palette name (v1: a tile id)."
67
+ }),
68
+ frames: t.list(t.json, { description: "Tiles it cycles through (names; v1: ids)." }),
36
69
  frameTime: t.f32({
37
70
  default: 0.2,
38
71
  min: 1e-3,
@@ -44,7 +77,7 @@ const TilemapDataSchema = defineSchema(
44
77
  )
45
78
  },
46
79
  {
47
- description: "Tile layers for a Tilemap: indices into its atlas, per-tile flags, animated tiles."
80
+ description: "Tile layers for a Tilemap: tiles named through a palette of atlas regions, per-tile flags, animated tiles. Saved as readable rows or compact base64."
48
81
  }
49
82
  );
50
83
  const MAX_EDITS = 4096;
@@ -93,66 +126,243 @@ class TileLayer {
93
126
  class TilemapData {
94
127
  layers;
95
128
  animations;
129
+ /**
130
+ * Atlas region names: tile id N draws the region named `palette[N - 1]` (0059). Undefined for
131
+ * maps made before palettes, whose ids are atlas regions + 1.
132
+ */
133
+ palette;
134
+ /** How the map is saved: readable rows (the default) or compact base64. */
135
+ encoding = "rows";
136
+ /** Tiles per chunk side in the rows encoding. */
137
+ chunkSize = 16;
96
138
  /** Bumps when the layers are replaced (hot reload). */
97
139
  version = 0;
98
- constructor(layers = [], animations = []) {
140
+ constructor(layers = [], animations = [], palette) {
99
141
  this.layers = layers;
100
142
  this.animations = animations;
143
+ this.palette = palette;
144
+ }
145
+ /**
146
+ * An empty map of `layers` layers, width × height tiles each. With a palette, tile ids name its
147
+ * entries; without, they're atlas regions + 1.
148
+ */
149
+ static create(width, height, layers = ["main"], palette) {
150
+ return new TilemapData(
151
+ layers.map((name) => new TileLayer(name, width, height)),
152
+ [],
153
+ palette ? [...palette] : void 0
154
+ );
155
+ }
156
+ /** The id of a palette name, adding it to the palette if it's new. Needs a palette. */
157
+ tileId(name) {
158
+ if (!this.palette) {
159
+ throw new ShardError("sprite/no-palette", "This tilemap names no tiles (version 1)", {
160
+ hint: "Save it once with its atlas (tilemapToJson(data, { atlas })) to give it a palette."
161
+ });
162
+ }
163
+ let i = this.palette.indexOf(name);
164
+ if (i === -1) {
165
+ i = this.palette.length;
166
+ this.palette.push(name);
167
+ }
168
+ return i + 1;
101
169
  }
102
- /** An empty map of `layers` layers, width × height tiles each. */
103
- static create(width, height, layers = ["main"]) {
104
- return new TilemapData(layers.map((name) => new TileLayer(name, width, height)));
170
+ /** The name a tile id draws: through the palette, or the atlas for version 1 maps. */
171
+ tileName(id, atlas) {
172
+ if (id === 0) return void 0;
173
+ return this.palette ? this.palette[id - 1] : atlas?.names[id - 1];
105
174
  }
175
+ /** A map from its file's JSON (`$schema`, an editor's pointer, is ignored). */
106
176
  static fromJson(json) {
177
+ if (json && typeof json === "object" && "$schema" in json) {
178
+ const { $schema: _, ...body } = json;
179
+ json = body;
180
+ }
107
181
  const v = TilemapDataSchema.deserialize(json);
182
+ const named = v.version >= 2;
183
+ const palette = named ? [...v.palette] : void 0;
184
+ const index = new Map((palette ?? []).map((name, i) => [name, i]));
108
185
  const layers = v.layers.map((l, i) => {
109
186
  const n = l.width * l.height;
110
- const tileBytes = fromBase64(l.tiles);
111
- if (tileBytes.length !== n * 2) {
112
- throw new ShardError(
113
- "sprite/invalid-tilemap",
114
- `Layer "${l.name}" has ${tileBytes.length / 2} tiles; ${l.width}\xD7${l.height} needs ${n}`,
115
- { path: `/layers/${i}/tiles` }
116
- );
117
- }
118
- const tiles = new Uint16Array(n);
119
- const view = new DataView(tileBytes.buffer, tileBytes.byteOffset, tileBytes.byteLength);
120
- for (let k = 0; k < n; k++) tiles[k] = view.getUint16(k * 2, true);
187
+ const path = `/layers/${i}`;
188
+ let tiles;
121
189
  let flags;
122
- if (l.flags) {
123
- flags = fromBase64(l.flags);
124
- if (flags.length !== n) {
125
- throw new ShardError(
126
- "sprite/invalid-tilemap",
127
- `Layer "${l.name}" has ${flags.length} flag bytes; ${l.width}\xD7${l.height} needs ${n}`,
128
- { path: `/layers/${i}/flags` }
129
- );
190
+ if (named && v.encoding === "rows") {
191
+ tiles = new Uint16Array(n);
192
+ flags = new Uint8Array(n);
193
+ const grid = { width: l.width, height: l.height, tiles, flags };
194
+ const chunks = l.chunks ?? {};
195
+ if (typeof chunks !== "object" || Array.isArray(chunks)) {
196
+ throw new ShardError("sprite/invalid-tilemap", 'Expected chunks by "cx,cy"', {
197
+ path: `${path}/chunks`
198
+ });
199
+ }
200
+ for (const [key, rows] of Object.entries(chunks)) {
201
+ const m = /^(\d+),(\d+)$/.exec(key);
202
+ const at = `${path}/chunks/${key}`;
203
+ if (!m) {
204
+ throw new ShardError("sprite/invalid-tilemap", `Bad chunk key "${key}"`, {
205
+ path: at,
206
+ hint: 'Chunk keys are "cx,cy": the chunk column and row from the top left.'
207
+ });
208
+ }
209
+ readChunkRows(grid, palette, index, Number(m[1]), Number(m[2]), v.chunkSize, rows, at);
210
+ }
211
+ } else {
212
+ tiles = tilesFromBase64(l.tiles, n, `${path}/tiles`, l.name);
213
+ flags = flagsFromBase64(l.flags, n, `${path}/flags`, l.name);
214
+ if (palette) {
215
+ for (let k = 0; k < n; k++) {
216
+ if (tiles[k] > palette.length) {
217
+ throw new ShardError(
218
+ "sprite/invalid-tilemap",
219
+ `Tile id ${tiles[k]} at (${k % l.width}, ${Math.floor(k / l.width)}) has no palette entry`,
220
+ { path: `${path}/tiles` }
221
+ );
222
+ }
223
+ }
130
224
  }
131
225
  }
132
226
  const layer = new TileLayer(l.name, l.width, l.height, tiles, flags);
133
227
  layer.occludes = l.occludes;
134
228
  return layer;
135
229
  });
136
- return new TilemapData(layers, v.animations);
230
+ const idOf = (value, at) => {
231
+ if (!named) {
232
+ if (typeof value !== "number") {
233
+ throw new ShardError("sprite/invalid-tilemap", "Expected a tile id", { path: at });
234
+ }
235
+ return value;
236
+ }
237
+ if (typeof value !== "string") {
238
+ throw new ShardError("sprite/invalid-tilemap", "Expected a palette name", { path: at });
239
+ }
240
+ let p = index.get(value);
241
+ if (p === void 0) {
242
+ p = palette.length;
243
+ palette.push(value);
244
+ index.set(value, p);
245
+ }
246
+ return p + 1;
247
+ };
248
+ const animations = v.animations.map((a, i) => ({
249
+ tile: idOf(a.tile, `/animations/${i}/tile`),
250
+ frames: a.frames.map((f, k) => idOf(f, `/animations/${i}/frames/${k}`)),
251
+ frameTime: a.frameTime
252
+ }));
253
+ const data = new TilemapData(layers, animations, palette);
254
+ data.encoding = named ? v.encoding : "base64";
255
+ data.chunkSize = v.chunkSize;
256
+ return data;
137
257
  }
138
- toJson() {
258
+ /**
259
+ * The map as version 2 JSON, in its encoding (or `options.encoding`). A version 1 map needs its
260
+ * atlas to name its tiles; its palette lists them in first use order. A map with a palette keeps
261
+ * it in order, so an edit that uses a known tile changes one row.
262
+ */
263
+ toJson(options = {}) {
264
+ const encoding = options.encoding ?? this.encoding;
265
+ let palette;
266
+ let remap;
267
+ if (this.palette) palette = this.palette;
268
+ else {
269
+ const atlas = options.atlas;
270
+ if (!atlas) {
271
+ throw new ShardError(
272
+ "sprite/tilemap-needs-atlas",
273
+ "Saving a version 1 tilemap needs its atlas",
274
+ {
275
+ hint: "Its tiles are atlas regions: pass the atlas so they can be named (the palette)."
276
+ }
277
+ );
278
+ }
279
+ palette = [];
280
+ const byRegion = /* @__PURE__ */ new Map();
281
+ const use = (id) => {
282
+ if (id === 0) return 0;
283
+ let p = byRegion.get(id);
284
+ if (p === void 0) {
285
+ const name2 = atlas.names[id - 1];
286
+ if (name2 === void 0) {
287
+ throw new ShardError(
288
+ "sprite/unknown-tile",
289
+ `Tile ${id} is past the atlas's ${atlas.names.length} regions`
290
+ );
291
+ }
292
+ p = palette.length;
293
+ palette.push(name2);
294
+ byRegion.set(id, p);
295
+ }
296
+ return p + 1;
297
+ };
298
+ for (const l of this.layers) for (let k = 0; k < l.tiles.length; k++) use(l.tiles[k]);
299
+ for (const a of this.animations) {
300
+ use(a.tile);
301
+ for (const f of a.frames) use(f);
302
+ }
303
+ remap = use;
304
+ }
305
+ if (encoding === "rows") {
306
+ for (const name2 of palette) {
307
+ if (!rowsCanName(name2)) {
308
+ throw new ShardError(
309
+ "sprite/unencodable-tile",
310
+ `Tile "${name2}" can't be written in rows`,
311
+ {
312
+ hint: 'Region names in rows have no spaces, ":", "*" or "+". Save with encoding base64.'
313
+ }
314
+ );
315
+ }
316
+ }
317
+ }
318
+ const idsOf = (l) => {
319
+ if (!remap) return l.tiles;
320
+ const out = new Uint16Array(l.tiles.length);
321
+ for (let k = 0; k < out.length; k++) out[k] = remap(l.tiles[k]);
322
+ return out;
323
+ };
324
+ const name = (id) => palette[(remap ? remap(id) : id) - 1];
139
325
  return {
326
+ version: 2,
327
+ encoding,
328
+ ...encoding === "rows" ? { chunkSize: this.chunkSize } : {},
329
+ palette: [...palette],
140
330
  layers: this.layers.map((l) => {
141
- const bytes = new Uint8Array(l.tiles.length * 2);
142
- const view = new DataView(bytes.buffer);
143
- for (let k = 0; k < l.tiles.length; k++) view.setUint16(k * 2, l.tiles[k], true);
144
- return {
145
- name: l.name,
146
- width: l.width,
147
- height: l.height,
148
- tiles: toBase64(bytes),
149
- flags: l.flags.some((f) => f !== 0) ? toBase64(l.flags) : "",
150
- ...l.occludes ? { occludes: true } : {}
331
+ const tiles = idsOf(l);
332
+ const head = { name: l.name, width: l.width, height: l.height };
333
+ const cells = encoding === "rows" ? {
334
+ chunks: layerChunks(
335
+ { width: l.width, height: l.height, tiles, flags: l.flags },
336
+ palette,
337
+ this.chunkSize
338
+ )
339
+ } : {
340
+ tiles: tilesToBase64(tiles),
341
+ flags: l.flags.some((f) => f !== 0) ? toBase64(l.flags) : ""
151
342
  };
343
+ return { ...head, ...cells, ...l.occludes ? { occludes: true } : {} };
152
344
  }),
153
- animations: this.animations
345
+ animations: this.animations.map((a) => ({
346
+ tile: name(a.tile),
347
+ frames: a.frames.map(name),
348
+ frameTime: a.frameTime
349
+ }))
154
350
  };
155
351
  }
352
+ sameAs(other) {
353
+ if (this.encoding !== other.encoding || this.chunkSize !== other.chunkSize || this.layers.length !== other.layers.length || JSON.stringify(this.palette) !== JSON.stringify(other.palette) || JSON.stringify(this.animations) !== JSON.stringify(other.animations))
354
+ return false;
355
+ for (let i = 0; i < this.layers.length; i++) {
356
+ const a = this.layers[i];
357
+ const b = other.layers[i];
358
+ if (a.name !== b.name || a.width !== b.width || a.height !== b.height) return false;
359
+ if (a.occludes !== b.occludes) return false;
360
+ for (let k = 0; k < a.tiles.length; k++) {
361
+ if (a.tiles[k] !== b.tiles[k] || a.flags[k] !== b.flags[k]) return false;
362
+ }
363
+ }
364
+ return true;
365
+ }
156
366
  /** The largest tile index any layer uses (for validating against an atlas). */
157
367
  maxTile() {
158
368
  let max = 0;
@@ -160,24 +370,28 @@ class TilemapData {
160
370
  for (let k = 0; k < l.tiles.length; k++) max = Math.max(max, l.tiles[k]);
161
371
  return max;
162
372
  }
373
+ /** Takes another map's content (hot reload). Identical content (a save reloading) changes nothing. */
163
374
  copyFrom(other) {
375
+ if (this.sameAs(other)) return;
164
376
  this.layers = other.layers;
165
377
  this.animations = other.animations;
378
+ this.palette = other.palette;
379
+ this.encoding = other.encoding;
380
+ this.chunkSize = other.chunkSize;
166
381
  this.version++;
167
382
  }
168
383
  }
169
- function fromBase64(s) {
170
- const bin = atob(s);
171
- const out = new Uint8Array(bin.length);
172
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
173
- return out;
384
+ function tileNames(data, atlas) {
385
+ if (data.palette) return data.palette;
386
+ if (atlas) return atlas.names;
387
+ throw new ShardError("sprite/tilemap-needs-atlas", "This tilemap names no tiles (version 1)", {
388
+ hint: "Give a Tilemap using it an atlas, or save it once with one (tilemapToText(data, { atlas }))."
389
+ });
174
390
  }
175
- function toBase64(bytes) {
176
- let s = "";
177
- for (let i = 0; i < bytes.length; i += 32768) {
178
- s += String.fromCharCode(...bytes.subarray(i, i + 32768));
179
- }
180
- return btoa(s);
391
+ function tilemapToText(data, options = {}) {
392
+ const json = data.toJson(options);
393
+ return `${JSON.stringify(options.schema === void 0 ? json : { $schema: options.schema, ...json }, null, 2)}
394
+ `;
181
395
  }
182
396
  class TilemapDataStore extends AssetStore {
183
397
  constructor() {
@@ -216,14 +430,20 @@ const Tilemap = defineComponent(
216
430
  layer: t.i16({
217
431
  description: "Draw-order band, like Sprite.layer (tilemaps draw first in a band)."
218
432
  }),
219
- lit: t.bool({
220
- default: true,
221
- description: "Lit by 2D lights under a Lighting2d camera."
433
+ lit: t.enum(["2d", "3d", "none"], {
434
+ description: "2d: lit by 2D lights under a Lighting2d camera. 3d: lit by 3D lights and shadows like a floor. none: drawn as the atlas is. On the ground (with a GroundLayer) there are no 2D lights: 2d and 3d both light it like a floor."
222
435
  })
223
436
  },
224
437
  {
225
- description: "Tile layers drawn over the entity's XY plane: tile (x, y) covers [x, x+1] \xD7 [\u2212y\u22121, \u2212y] tile sizes, rows going down from the top.",
226
- requires: [Transform, Visibility]
438
+ description: "Tile layers drawn over the entity's XY plane: tile (x, y) covers [x, x+1] \xD7 [\u2212y\u22121, \u2212y] tile sizes, rows going down from the top. With a GroundLayer (0059), they draw in the ground phase among the tabletop's bands (lay them flat with tilemapOnGround).",
439
+ requires: [Transform, Visibility],
440
+ version: 2,
441
+ // Version 1: lit was a flag for 2D lighting.
442
+ migrate: (_from, json) => {
443
+ const v = { ...json };
444
+ if (typeof v.lit === "boolean") v.lit = v.lit ? "2d" : "none";
445
+ return v;
446
+ }
227
447
  }
228
448
  );
229
449
  function layerOf(world, tilemap, layer) {
@@ -252,6 +472,36 @@ function setTile(world, tilemap, x, y, tile, options = {}) {
252
472
  function tileAt(world, tilemap, x, y, layer = 0) {
253
473
  return layerOf(world, tilemap, layer).get(x, y);
254
474
  }
475
+ function unknownTiles(data, atlas) {
476
+ const out = [];
477
+ if (!data.palette) return out;
478
+ for (let i = 0; i < data.palette.length; i++) {
479
+ const name = data.palette[i];
480
+ if (atlas.region(name) !== -1) continue;
481
+ const id = i + 1;
482
+ let where;
483
+ for (let li = 0; li < data.layers.length && !where; li++) {
484
+ const l2 = data.layers[li];
485
+ const at = l2.tiles.indexOf(id);
486
+ if (at !== -1) where = { layer: li, x: at % l2.width, y: Math.floor(at / l2.width) };
487
+ }
488
+ if (!where) continue;
489
+ const l = data.layers[where.layer];
490
+ const cs = data.chunkSize;
491
+ const path = data.encoding === "rows" ? `/layers/${where.layer}/chunks/${Math.floor(where.x / cs)},${Math.floor(where.y / cs)}/${where.y % cs}` : `/layers/${where.layer}/tiles`;
492
+ out.push(
493
+ new ShardError(
494
+ "sprite/unknown-tile",
495
+ `Layer "${l.name}", cell (${where.x}, ${where.y}): tile "${name}" isn't a region of the atlas`,
496
+ {
497
+ path,
498
+ hint: "Rename it to a region the atlas has, or add the region to the atlas."
499
+ }
500
+ )
501
+ );
502
+ }
503
+ return out;
504
+ }
255
505
  export {
256
506
  TileFlags,
257
507
  TileLayer,
@@ -263,5 +513,8 @@ export {
263
513
  TilemapDataStore,
264
514
  TilemapDatas,
265
515
  setTile,
266
- tileAt
516
+ tileAt,
517
+ tileNames,
518
+ tilemapToText,
519
+ unknownTiles
267
520
  };
@@ -0,0 +1,11 @@
1
+ import type { ShardError, World } from '@aethervtt/shard-core';
2
+ /**
3
+ * Checks each Tilemap's data against its atlas (0059): a palette name the atlas has no region
4
+ * for is `sprite/unknown-tile`, naming the layer, the cell and the name, with a JSON pointer to
5
+ * the cell's row in the data file. Scenes and prefabs say which atlas draws which data, so the
6
+ * check runs over their files. Loads what it checks.
7
+ */
8
+ export declare function validateTilemaps(world: World, files: readonly unknown[]): Promise<{
9
+ source: string;
10
+ errors: ShardError[];
11
+ }[]>;
@@ -0,0 +1,49 @@
1
+ import { assetServer } from "@aethervtt/shard-assets";
2
+ import { TextureAtlas } from "./atlas.js";
3
+ import { TilemapData, unknownTiles } from "./tilemap.js";
4
+ function tilemapsIn(json, out) {
5
+ if (Array.isArray(json)) {
6
+ for (const item of json) tilemapsIn(item, out);
7
+ return;
8
+ }
9
+ if (!json || typeof json !== "object") return;
10
+ for (const [key, value] of Object.entries(json)) {
11
+ if (key === "sprite/Tilemap" && value && typeof value === "object") {
12
+ const v = value;
13
+ if (v.data && v.atlas) out.push({ data: v.data, atlas: v.atlas });
14
+ } else tilemapsIn(value, out);
15
+ }
16
+ }
17
+ async function validateTilemaps(world, files) {
18
+ const server = assetServer(world);
19
+ const found = [];
20
+ for (const file of files) tilemapsIn(file, found);
21
+ const seen = /* @__PURE__ */ new Set();
22
+ const out = /* @__PURE__ */ new Map();
23
+ for (const pair of found) {
24
+ const data = server.entry(pair.data);
25
+ const atlas = server.entry(pair.atlas);
26
+ if (!data || !atlas || data.type !== "TilemapData" || atlas.type !== "TextureAtlas") continue;
27
+ const key = `${data.guid}|${atlas.guid}`;
28
+ if (seen.has(key)) continue;
29
+ seen.add(key);
30
+ try {
31
+ await Promise.all([server.load(data.guid), server.load(atlas.guid)]);
32
+ } catch {
33
+ continue;
34
+ }
35
+ const d = server.item(data.guid);
36
+ const a = server.item(atlas.guid);
37
+ if (!(d instanceof TilemapData) || !(a instanceof TextureAtlas)) continue;
38
+ const errors = unknownTiles(d, a);
39
+ if (errors.length === 0) continue;
40
+ const source = data.source ?? data.path;
41
+ const list = out.get(source) ?? [];
42
+ for (const e of errors) if (!list.some((x) => x.message === e.message)) list.push(e);
43
+ out.set(source, list);
44
+ }
45
+ return [...out].map(([source, errors]) => ({ source, errors }));
46
+ }
47
+ export {
48
+ validateTilemaps
49
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aethervtt/shard-sprite",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -16,13 +16,13 @@
16
16
  "README.md"
17
17
  ],
18
18
  "dependencies": {
19
- "@aethervtt/shard-assets": "0.0.1",
20
- "@aethervtt/shard-core": "0.0.1",
21
- "@aethervtt/shard-gpu": "0.0.1",
22
- "@aethervtt/shard-render": "0.0.1",
23
- "@aethervtt/shard-runtime": "0.0.1",
24
- "@aethervtt/shard-texture": "0.0.1",
25
- "@aethervtt/shard-transform": "0.0.1"
19
+ "@aethervtt/shard-assets": "0.2.0",
20
+ "@aethervtt/shard-core": "0.2.0",
21
+ "@aethervtt/shard-gpu": "0.2.0",
22
+ "@aethervtt/shard-render": "0.2.0",
23
+ "@aethervtt/shard-runtime": "0.2.0",
24
+ "@aethervtt/shard-texture": "0.2.0",
25
+ "@aethervtt/shard-transform": "0.2.0"
26
26
  },
27
27
  "repository": {
28
28
  "type": "git",
@@ -34,6 +34,6 @@
34
34
  "provenance": true
35
35
  },
36
36
  "shard": {
37
- "buildSha": "d6c5c6aef4675575c878b02cf2c8f738b4190229"
37
+ "buildSha": "32c22a3944ed23f5d1baa90bf7cc9fae724f5fd8"
38
38
  }
39
39
  }