@vworlds/vecs-phaser-server 1.0.35 → 1.0.37

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/asset.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Base class for every asset the server owns. v1.0.36 has one concrete kind —
3
+ * `TilesetAsset` — but future kinds (audio, etc.) extend this with their own
4
+ * `Asset` subclass and one `getX(key)` method each on `AssetManager`.
5
+ *
6
+ * `id` is server-assigned, stable, and append-only: allocated the first time an
7
+ * asset is loaded, never reused or reordered, so a future in-band "asset added"
8
+ * message can extend the catalog at runtime without disturbing v1.0.36.
9
+ *
10
+ * `key` is the human authoring/debug name — it never crosses the wire; the
11
+ * client keys Phaser textures by the numeric `id`.
12
+ */
13
+ export declare abstract class Asset {
14
+ /**
15
+ * Stable, append-only wire id. Server-assigned on first load; reused on
16
+ * subsequent `getTileset(key)` calls.
17
+ */
18
+ readonly id: number;
19
+ /** Human authoring/debug key (filename stem). Server-only. */
20
+ readonly key: string;
21
+ /**
22
+ * @param id - Server-assigned stable wire id.
23
+ * @param key - Human authoring/debug key.
24
+ */
25
+ constructor(id: number, key: string);
26
+ }
package/asset.js ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Base class for every asset the server owns. v1.0.36 has one concrete kind —
3
+ * `TilesetAsset` — but future kinds (audio, etc.) extend this with their own
4
+ * `Asset` subclass and one `getX(key)` method each on `AssetManager`.
5
+ *
6
+ * `id` is server-assigned, stable, and append-only: allocated the first time an
7
+ * asset is loaded, never reused or reordered, so a future in-band "asset added"
8
+ * message can extend the catalog at runtime without disturbing v1.0.36.
9
+ *
10
+ * `key` is the human authoring/debug name — it never crosses the wire; the
11
+ * client keys Phaser textures by the numeric `id`.
12
+ */
13
+ export class Asset {
14
+ /**
15
+ * @param id - Server-assigned stable wire id.
16
+ * @param key - Human authoring/debug key.
17
+ */
18
+ constructor(id, key) {
19
+ this.id = id;
20
+ this.key = key;
21
+ }
22
+ }
23
+ //# sourceMappingURL=asset.js.map
package/asset.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset.js","sourceRoot":"","sources":["../src/asset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,OAAgB,KAAK;IAUzB;;;OAGG;IACH,YAAY,EAAU,EAAE,GAAW;QACjC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF"}
@@ -0,0 +1,91 @@
1
+ import { type AssetCatalog } from "@vworlds/vecs-phaser";
2
+ import { TilesetAsset } from "./tileset_asset.js";
3
+ /** Error thrown when a tileset cannot be found on disk. */
4
+ export declare class TilesetNotFoundError extends Error {
5
+ /** @param message - Human-readable error message. */
6
+ constructor(message: string);
7
+ }
8
+ /** Error thrown when a cached/loaded asset is not the requested kind. */
9
+ export declare class AssetKindMismatchError extends Error {
10
+ /** @param message - Human-readable error message. */
11
+ constructor(message: string);
12
+ }
13
+ /** Error thrown when a tileset violates the v1.0.36 single-image scope guard. */
14
+ export declare class ImageCollectionTilesetError extends Error {
15
+ /** @param message - Human-readable error message. */
16
+ constructor(message: string);
17
+ }
18
+ /** Constructor options for {@link AssetManager}. */
19
+ export interface AssetManagerOptions {
20
+ /** Root asset directory (e.g. `"assets"`). Tilesets live under `tilesets/`. */
21
+ assetsPath: string;
22
+ }
23
+ /**
24
+ * Server-side asset loader + cache of typed asset handles. v1.0.36 has one asset
25
+ * type — **tileset**; future kinds add their own `Asset` subclass and one
26
+ * `getX(key)` method each.
27
+ *
28
+ * `getTileset(key)` reads `assetsPath/tilesets/<key>.tsj` (falling back to
29
+ * `<key>.json`), parses with a `JSON.parse` reviver that constructs live
30
+ * `TilesetAsset`/`Tile`/`MapObject` instances (not plain data bags), assigns a
31
+ * stable append-only `id`, and caches by the human key so a second call returns
32
+ * the same handle. Image **bytes** are never read server-side — only metadata;
33
+ * bytes are served over HTTP by `mount`.
34
+ *
35
+ * `toCatalog(worldName)` enumerates cached assets into the wire DTO
36
+ * (`AssetCatalog`), stripping server-only metadata. `mount(app, worldName)`
37
+ * registers the catalog JSON route and a static file route over `assetsPath`.
38
+ */
39
+ export declare class AssetManager {
40
+ /** Root asset directory. */
41
+ readonly assetsPath: string;
42
+ /** Cache of loaded assets keyed by human key (same handle on re-get). */
43
+ private readonly _cache;
44
+ /** Next server-assigned wire id (append-only, starts at 1). */
45
+ private _nextId;
46
+ /**
47
+ * @param options - `{ assetsPath }` root asset directory.
48
+ */
49
+ constructor(options: AssetManagerOptions);
50
+ /**
51
+ * Load (or return cached) `TilesetAsset` by human key. Reads
52
+ * `assetsPath/tilesets/<key>.tsj`, falling back to `<key>.json`. The first call
53
+ * parses via `JSON.parse(text, reviver)` constructing live instances, assigns
54
+ * a stable `id`, and caches; subsequent calls return the same handle.
55
+ *
56
+ * @param key - Human key (filename stem).
57
+ * @returns The loaded `TilesetAsset`.
58
+ * @throws {TilesetNotFoundError} when neither `<key>.tsj` nor `<key>.json` exists.
59
+ * @throws {AssetKindMismatchError} when a different asset kind is cached under `key`.
60
+ * @throws {ImageCollectionTilesetError} when the tileset is an image-collection.
61
+ */
62
+ getTileset(key: string): TilesetAsset;
63
+ /**
64
+ * Enumerate all cached assets into a wire `AssetCatalog` DTO, stripping
65
+ * server-only metadata (no properties/objects/animation/class on the
66
+ * descriptors). Each spritesheet descriptor's `url` is the server path the
67
+ * static route serves.
68
+ *
69
+ * @param worldName - Name of the world this catalog describes.
70
+ * @param apiBasePath - API base path (default `"/rtc/v1/world"`).
71
+ * @returns The `AssetCatalog` DTO.
72
+ */
73
+ toCatalog(worldName: string, apiBasePath?: string): AssetCatalog;
74
+ /**
75
+ * Register the catalog JSON route and a static file route over `assetsPath`
76
+ * on the given Express app, under the per-world `worldPath(apiBasePath,
77
+ * worldName)`.
78
+ *
79
+ * - `GET {worldPath}/assets` → `toCatalog(worldName, apiBasePath)` JSON.
80
+ * - `{worldPath}/assets/files` → `express.static(assetsPath)` (serves images).
81
+ *
82
+ * @param app - Express app instance.
83
+ * @param worldName - Name of the world.
84
+ * @param apiBasePath - API base path (default `"/rtc/v1/world"`).
85
+ */
86
+ mount(app: import("express").Express, worldName: string, apiBasePath?: string): void;
87
+ /** Load a `TilesetAsset` from disk, parse with the reviver, assign an id. */
88
+ private _loadTileset;
89
+ /** Build a live `TilesetAsset` from raw input, applying scope guards + defaults. */
90
+ private _buildTileset;
91
+ }
@@ -0,0 +1,198 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, isAbsolute, join, normalize, relative, sep } from "node:path";
3
+ import express from "express";
4
+ import { worldPath } from "@vworlds/vecs-protocol";
5
+ import { TilesetAsset, buildTiles } from "./tileset_asset.js";
6
+ /** Error thrown when a tileset cannot be found on disk. */
7
+ export class TilesetNotFoundError extends Error {
8
+ /** @param message - Human-readable error message. */
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "TilesetNotFoundError";
12
+ }
13
+ }
14
+ /** Error thrown when a cached/loaded asset is not the requested kind. */
15
+ export class AssetKindMismatchError extends Error {
16
+ /** @param message - Human-readable error message. */
17
+ constructor(message) {
18
+ super(message);
19
+ this.name = "AssetKindMismatchError";
20
+ }
21
+ }
22
+ /** Error thrown when a tileset violates the v1.0.36 single-image scope guard. */
23
+ export class ImageCollectionTilesetError extends Error {
24
+ /** @param message - Human-readable error message. */
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "ImageCollectionTilesetError";
28
+ }
29
+ }
30
+ /**
31
+ * Server-side asset loader + cache of typed asset handles. v1.0.36 has one asset
32
+ * type — **tileset**; future kinds add their own `Asset` subclass and one
33
+ * `getX(key)` method each.
34
+ *
35
+ * `getTileset(key)` reads `assetsPath/tilesets/<key>.tsj` (falling back to
36
+ * `<key>.json`), parses with a `JSON.parse` reviver that constructs live
37
+ * `TilesetAsset`/`Tile`/`MapObject` instances (not plain data bags), assigns a
38
+ * stable append-only `id`, and caches by the human key so a second call returns
39
+ * the same handle. Image **bytes** are never read server-side — only metadata;
40
+ * bytes are served over HTTP by `mount`.
41
+ *
42
+ * `toCatalog(worldName)` enumerates cached assets into the wire DTO
43
+ * (`AssetCatalog`), stripping server-only metadata. `mount(app, worldName)`
44
+ * registers the catalog JSON route and a static file route over `assetsPath`.
45
+ */
46
+ export class AssetManager {
47
+ /**
48
+ * @param options - `{ assetsPath }` root asset directory.
49
+ */
50
+ constructor(options) {
51
+ /** Cache of loaded assets keyed by human key (same handle on re-get). */
52
+ this._cache = new Map();
53
+ /** Next server-assigned wire id (append-only, starts at 1). */
54
+ this._nextId = 1;
55
+ this.assetsPath = options.assetsPath;
56
+ }
57
+ /**
58
+ * Load (or return cached) `TilesetAsset` by human key. Reads
59
+ * `assetsPath/tilesets/<key>.tsj`, falling back to `<key>.json`. The first call
60
+ * parses via `JSON.parse(text, reviver)` constructing live instances, assigns
61
+ * a stable `id`, and caches; subsequent calls return the same handle.
62
+ *
63
+ * @param key - Human key (filename stem).
64
+ * @returns The loaded `TilesetAsset`.
65
+ * @throws {TilesetNotFoundError} when neither `<key>.tsj` nor `<key>.json` exists.
66
+ * @throws {AssetKindMismatchError} when a different asset kind is cached under `key`.
67
+ * @throws {ImageCollectionTilesetError} when the tileset is an image-collection.
68
+ */
69
+ getTileset(key) {
70
+ const cached = this._cache.get(key);
71
+ if (cached !== undefined) {
72
+ if (!(cached instanceof TilesetAsset)) {
73
+ throw new AssetKindMismatchError(`Asset "${key}" is not a TilesetAsset (got ${cached.constructor.name})`);
74
+ }
75
+ return cached;
76
+ }
77
+ const asset = this._loadTileset(key);
78
+ this._cache.set(key, asset);
79
+ return asset;
80
+ }
81
+ /**
82
+ * Enumerate all cached assets into a wire `AssetCatalog` DTO, stripping
83
+ * server-only metadata (no properties/objects/animation/class on the
84
+ * descriptors). Each spritesheet descriptor's `url` is the server path the
85
+ * static route serves.
86
+ *
87
+ * @param worldName - Name of the world this catalog describes.
88
+ * @param apiBasePath - API base path (default `"/rtc/v1/world"`).
89
+ * @returns The `AssetCatalog` DTO.
90
+ */
91
+ toCatalog(worldName, apiBasePath = "/rtc/v1/world") {
92
+ const base = worldPath(apiBasePath, worldName);
93
+ const assets = [];
94
+ for (const asset of this._cache.values()) {
95
+ if (asset instanceof TilesetAsset) {
96
+ const descriptor = {
97
+ id: asset.id,
98
+ key: asset.key,
99
+ kind: "spritesheet",
100
+ url: `${base}/assets/files/${asset.image}`,
101
+ frameWidth: asset.frameWidth,
102
+ frameHeight: asset.frameHeight,
103
+ margin: asset.margin,
104
+ spacing: asset.spacing,
105
+ columns: asset.columns,
106
+ tileCount: asset.tileCount,
107
+ imageWidth: asset.imageWidth,
108
+ imageHeight: asset.imageHeight,
109
+ };
110
+ assets.push(descriptor);
111
+ }
112
+ }
113
+ return { worldName, assets };
114
+ }
115
+ /**
116
+ * Register the catalog JSON route and a static file route over `assetsPath`
117
+ * on the given Express app, under the per-world `worldPath(apiBasePath,
118
+ * worldName)`.
119
+ *
120
+ * - `GET {worldPath}/assets` → `toCatalog(worldName, apiBasePath)` JSON.
121
+ * - `{worldPath}/assets/files` → `express.static(assetsPath)` (serves images).
122
+ *
123
+ * @param app - Express app instance.
124
+ * @param worldName - Name of the world.
125
+ * @param apiBasePath - API base path (default `"/rtc/v1/world"`).
126
+ */
127
+ mount(app, worldName, apiBasePath = "/rtc/v1/world") {
128
+ const base = worldPath(apiBasePath, worldName);
129
+ app.get(`${base}/assets`, (_req, res) => {
130
+ res.json(this.toCatalog(worldName, apiBasePath));
131
+ });
132
+ app.use(`${base}/assets/files`, express.static(this.assetsPath));
133
+ }
134
+ /** Load a `TilesetAsset` from disk, parse with the reviver, assign an id. */
135
+ _loadTileset(key) {
136
+ const tsjPath = join(this.assetsPath, "tilesets", `${key}.tsj`);
137
+ const jsonPath = join(this.assetsPath, "tilesets", `${key}.json`);
138
+ let text;
139
+ let filePath;
140
+ try {
141
+ text = readFileSync(tsjPath, "utf8");
142
+ filePath = tsjPath;
143
+ }
144
+ catch {
145
+ try {
146
+ text = readFileSync(jsonPath, "utf8");
147
+ filePath = jsonPath;
148
+ }
149
+ catch {
150
+ throw new TilesetNotFoundError(`No tileset "${key}" found at ${tsjPath} or ${jsonPath}`);
151
+ }
152
+ }
153
+ const tileset = JSON.parse(text, (revKey, value) => revKey === "" ? this._buildTileset(key, filePath, value) : value);
154
+ return tileset;
155
+ }
156
+ /** Build a live `TilesetAsset` from raw input, applying scope guards + defaults. */
157
+ _buildTileset(key, filePath, raw) {
158
+ if (raw.image === undefined || raw.image === "") {
159
+ throw new ImageCollectionTilesetError(`Tileset "${key}" has no top-level image (image-collection tilesets are not supported in v1.0.36)`);
160
+ }
161
+ if (raw.tiles) {
162
+ for (const tile of raw.tiles) {
163
+ if (tile.image !== undefined && tile.image !== "") {
164
+ throw new ImageCollectionTilesetError(`Tileset "${key}" tile ${tile.id} carries its own image (image-collection tilesets are not supported in v1.0.36)`);
165
+ }
166
+ }
167
+ }
168
+ const tilesetImage = raw.image;
169
+ const resolvedImage = resolveImageRelative(this.assetsPath, filePath, tilesetImage);
170
+ const tiles = buildTiles(raw.tiles);
171
+ const id = this._nextId++;
172
+ return new TilesetAsset(id, key, resolvedImage, raw.tilewidth ?? 0, raw.tileheight ?? 0, raw.margin ?? 0, raw.spacing ?? 0, raw.columns ?? 0, raw.tilecount ?? 0, raw.imagewidth ?? 0, raw.imageheight ?? 0, raw.name ?? "",
173
+ // The tileset "Class" comes from `class` only. A tileset's top-level
174
+ // `type` is Tiled's file-format discriminator (`"tileset"`/`"map"`), not a
175
+ // class, so it must NOT be used as a fallback (unlike a *tile*'s `type`,
176
+ // which is that tile's class — see buildTile in tileset_asset.ts).
177
+ raw.class ?? "", raw.properties ?? [], tiles);
178
+ }
179
+ }
180
+ /**
181
+ * Resolve a tileset `image` path: the `image` field is relative to the `.tsj`
182
+ * file location; express it relative to `assetsPath` in POSIX form.
183
+ *
184
+ * Example: `.tsj` at `assets/tilesets/ship.tsj` + image `ship.png` ⇒
185
+ * `"tilesets/ship.png"`.
186
+ *
187
+ * @param assetsPath - Root asset directory.
188
+ * @param filePath - Absolute or relative path to the `.tsj`/`.json` file.
189
+ * @param image - Image path relative to the `.tsj` (Tiled `image` field).
190
+ * @returns Image path relative to `assetsPath`, POSIX-separated.
191
+ */
192
+ function resolveImageRelative(assetsPath, filePath, image) {
193
+ const fileDir = dirname(filePath);
194
+ const absoluteImage = isAbsolute(image) ? image : join(fileDir, image);
195
+ const rel = relative(assetsPath, absoluteImage);
196
+ return normalize(rel).split(sep).join("/");
197
+ }
198
+ //# sourceMappingURL=asset_manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset_manager.js","sourceRoot":"","sources":["../src/asset_manager.ts"],"names":[],"mappings":"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"}
package/index.d.ts CHANGED
@@ -1 +1,7 @@
1
1
  export { PhaserServerModule } from "./PhaserServerModule.js";
2
+ export { Asset } from "./asset.js";
3
+ export { MapObject, Tile } from "./tile.js";
4
+ export { TilesetAsset } from "./tileset_asset.js";
5
+ export { AssetManager, AssetKindMismatchError, ImageCollectionTilesetError, TilesetNotFoundError, } from "./asset_manager.js";
6
+ export type { AssetManagerOptions } from "./asset_manager.js";
7
+ export type { AnyProperty, Frame, Point, Property, PropertyType, Tile as TileIface, Tileset, } from "./types/tileset.js";
package/index.js CHANGED
@@ -1,2 +1,6 @@
1
1
  export { PhaserServerModule } from "./PhaserServerModule.js";
2
+ export { Asset } from "./asset.js";
3
+ export { MapObject, Tile } from "./tile.js";
4
+ export { TilesetAsset } from "./tileset_asset.js";
5
+ export { AssetManager, AssetKindMismatchError, ImageCollectionTilesetError, TilesetNotFoundError, } from "./asset_manager.js";
2
6
  //# sourceMappingURL=index.js.map
package/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EACL,YAAY,EACZ,sBAAsB,EACtB,2BAA2B,EAC3B,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vworlds/vecs-phaser-server",
3
- "version": "1.0.35",
3
+ "version": "1.0.37",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "types": "./index.d.ts",
@@ -15,9 +15,13 @@
15
15
  "url": "git+https://github.com/vworlds/vecs.git"
16
16
  },
17
17
  "dependencies": {
18
- "@vworlds/vecs-phaser": "1.0.35",
19
- "@vworlds/vecs-physics": "1.0.35",
20
- "@vworlds/vecs-server": "1.0.35"
18
+ "@vworlds/vecs-phaser": "1.0.37",
19
+ "@vworlds/vecs-physics": "1.0.37",
20
+ "@vworlds/vecs-protocol": "1.0.37",
21
+ "@vworlds/vecs-server": "1.0.37"
22
+ },
23
+ "peerDependencies": {
24
+ "express": "^5.2.1"
21
25
  },
22
26
  "license": "MIT"
23
27
  }
package/tile.d.ts ADDED
@@ -0,0 +1,94 @@
1
+ import { type AnyProperty, type Frame, type MapObject as MapObjectIface, type Tile as TileIface } from "./types/tileset.js";
2
+ /**
3
+ * Concrete `MapObject` — a collision/anchor shape on a tile. `implements` the
4
+ * vendored `MapObject` interface (no `?`): sparse Tiled shape flags become
5
+ * non-null defaults (`false`/`[]`/`0`/`""`) supplied at construction time.
6
+ *
7
+ * A plain rectangle has none of `ellipse`/`point`/`polygon`/`polyline` set. A
8
+ * circle is an ellipse with equal `width`/`height` (Tiled has no dedicated
9
+ * circle flag).
10
+ */
11
+ export declare class MapObject implements MapObjectIface {
12
+ /** Unique id across all objects in the tileset. */
13
+ readonly id: number;
14
+ /** X coordinate (px). */
15
+ x: number;
16
+ /** Y coordinate (px). */
17
+ y: number;
18
+ /** Width (px); `0` when Tiled omits it. */
19
+ width: number;
20
+ /** Height (px); `0` when Tiled omits it. */
21
+ height: number;
22
+ /** Rotation in degrees clockwise; `0` when Tiled omits it. */
23
+ rotation: number;
24
+ /** Name; `""` when Tiled omits it. */
25
+ name: string;
26
+ /** Object "Class"; `""` when Tiled omits it. */
27
+ type: string;
28
+ /** `true` if ellipse (a circle is an ellipse with equal dims). */
29
+ ellipse: boolean;
30
+ /** `true` if point. */
31
+ point: boolean;
32
+ /** Polygon points; `[]` when not a polygon. */
33
+ polygon: {
34
+ x: number;
35
+ y: number;
36
+ }[];
37
+ /** Polyline points; `[]` when not a polyline. */
38
+ polyline: {
39
+ x: number;
40
+ y: number;
41
+ }[];
42
+ /**
43
+ * @param id - Unique id across all objects in the tileset.
44
+ * @param x - X coordinate (px).
45
+ * @param y - Y coordinate (px).
46
+ * @param width - Width (px).
47
+ * @param height - Height (px).
48
+ * @param rotation - Rotation in degrees clockwise.
49
+ * @param name - Name.
50
+ * @param type - Object "Class".
51
+ * @param ellipse - `true` if ellipse.
52
+ * @param point - `true` if point.
53
+ * @param polygon - Polygon points (`[]` when not a polygon).
54
+ * @param polyline - Polyline points (`[]` when not a polyline).
55
+ */
56
+ constructor(id: number, x: number, y: number, width: number, height: number, rotation: number, name: string, type: string, ellipse: boolean, point: boolean, polygon: {
57
+ x: number;
58
+ y: number;
59
+ }[], polyline: {
60
+ x: number;
61
+ y: number;
62
+ }[]);
63
+ }
64
+ /**
65
+ * Concrete `Tile` — a single tile in a `TilesetAsset`, carrying the per-tile
66
+ * Tiled metadata the server reads (game-logic data) but the wire never
67
+ * carries. `implements` the vendored `Tile` interface (no `?`): sparse Tiled
68
+ * fields become non-null empty defaults (`""`/`[]`/empty `Map`) supplied at
69
+ * construction time.
70
+ *
71
+ * `id` equals the Phaser spritesheet frame index (row-major), so
72
+ * `set(Image, { texture: ship.id, frame: tileId })` shows this exact tile and
73
+ * `tileset.tile(tileId)` returns its metadata.
74
+ */
75
+ export declare class Tile implements TileIface {
76
+ /** Local tile id (== Phaser frame index, row-major). */
77
+ readonly id: number;
78
+ /** Tile "Class" (Tiled `class`/`type`); `""` when absent. */
79
+ class: string;
80
+ /** Typed properties, preserved as-is; `[]` when absent. */
81
+ properties: AnyProperty[];
82
+ /** Collision/anchor shapes keyed by `MapObject.id`; empty `Map` when absent. */
83
+ objects: Map<number, MapObject>;
84
+ /** Animation frames (captured for the future `Sprite` feature); `[]` when absent. */
85
+ animation: Frame[];
86
+ /**
87
+ * @param id - Local tile id (== Phaser frame index).
88
+ * @param classField - Tiled `class`/`type` (`""` when absent).
89
+ * @param properties - Typed properties (`[]` when absent).
90
+ * @param objects - Collision/anchor shapes keyed by `MapObject.id` (empty `Map` when absent).
91
+ * @param animation - Animation frames (`[]` when absent).
92
+ */
93
+ constructor(id: number, classField: string, properties: AnyProperty[], objects: Map<number, MapObject>, animation: Frame[]);
94
+ }
package/tile.js ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Concrete `MapObject` — a collision/anchor shape on a tile. `implements` the
3
+ * vendored `MapObject` interface (no `?`): sparse Tiled shape flags become
4
+ * non-null defaults (`false`/`[]`/`0`/`""`) supplied at construction time.
5
+ *
6
+ * A plain rectangle has none of `ellipse`/`point`/`polygon`/`polyline` set. A
7
+ * circle is an ellipse with equal `width`/`height` (Tiled has no dedicated
8
+ * circle flag).
9
+ */
10
+ export class MapObject {
11
+ /**
12
+ * @param id - Unique id across all objects in the tileset.
13
+ * @param x - X coordinate (px).
14
+ * @param y - Y coordinate (px).
15
+ * @param width - Width (px).
16
+ * @param height - Height (px).
17
+ * @param rotation - Rotation in degrees clockwise.
18
+ * @param name - Name.
19
+ * @param type - Object "Class".
20
+ * @param ellipse - `true` if ellipse.
21
+ * @param point - `true` if point.
22
+ * @param polygon - Polygon points (`[]` when not a polygon).
23
+ * @param polyline - Polyline points (`[]` when not a polyline).
24
+ */
25
+ constructor(id, x, y, width, height, rotation, name, type, ellipse, point, polygon, polyline) {
26
+ this.id = id;
27
+ this.x = x;
28
+ this.y = y;
29
+ this.width = width;
30
+ this.height = height;
31
+ this.rotation = rotation;
32
+ this.name = name;
33
+ this.type = type;
34
+ this.ellipse = ellipse;
35
+ this.point = point;
36
+ this.polygon = polygon;
37
+ this.polyline = polyline;
38
+ }
39
+ }
40
+ /**
41
+ * Concrete `Tile` — a single tile in a `TilesetAsset`, carrying the per-tile
42
+ * Tiled metadata the server reads (game-logic data) but the wire never
43
+ * carries. `implements` the vendored `Tile` interface (no `?`): sparse Tiled
44
+ * fields become non-null empty defaults (`""`/`[]`/empty `Map`) supplied at
45
+ * construction time.
46
+ *
47
+ * `id` equals the Phaser spritesheet frame index (row-major), so
48
+ * `set(Image, { texture: ship.id, frame: tileId })` shows this exact tile and
49
+ * `tileset.tile(tileId)` returns its metadata.
50
+ */
51
+ export class Tile {
52
+ /**
53
+ * @param id - Local tile id (== Phaser frame index).
54
+ * @param classField - Tiled `class`/`type` (`""` when absent).
55
+ * @param properties - Typed properties (`[]` when absent).
56
+ * @param objects - Collision/anchor shapes keyed by `MapObject.id` (empty `Map` when absent).
57
+ * @param animation - Animation frames (`[]` when absent).
58
+ */
59
+ constructor(id, classField, properties, objects, animation) {
60
+ this.id = id;
61
+ this.class = classField;
62
+ this.properties = properties;
63
+ this.objects = objects;
64
+ this.animation = animation;
65
+ }
66
+ }
67
+ //# sourceMappingURL=tile.js.map
package/tile.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tile.js","sourceRoot":"","sources":["../src/tile.ts"],"names":[],"mappings":"AAOA;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IAqCpB;;;;;;;;;;;;;OAaG;IACH,YACE,EAAU,EACV,CAAS,EACT,CAAS,EACT,KAAa,EACb,MAAc,EACd,QAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,OAAgB,EAChB,KAAc,EACd,OAAmC,EACnC,QAAoC;QAEpC,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;CACF;AAED;;;;;;;;;;GAUG;AACH,MAAM,OAAO,IAAI;IAgBf;;;;;;OAMG;IACH,YACE,EAAU,EACV,UAAkB,EAClB,UAAyB,EACzB,OAA+B,EAC/B,SAAkB;QAElB,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC;QACxB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF"}
@@ -0,0 +1,86 @@
1
+ import { Asset } from "./asset.js";
2
+ import { Tile } from "./tile.js";
3
+ import { type AnyProperty, type Tileset, type TileRaw } from "./types/tileset.js";
4
+ /**
5
+ * Concrete `TilesetAsset` — a single-image Tiled tileset ingested as a
6
+ * spritesheet. `extends Asset` (carries `id`/`key`) and `implements` the
7
+ * vendored `Tileset` interface (no `?`): sparse Tiled fields become non-null
8
+ * empty defaults (`""`/`[]`) supplied at construction time.
9
+ *
10
+ * Field-name mapping: Tiled `tilewidth`→`frameWidth`, `tileheight`→
11
+ * `frameHeight`, `tilecount`→`tileCount`, `imagewidth`→`imageWidth`,
12
+ * `imageheight`→`imageHeight`. `image` is the resolved image path relative to
13
+ * `assetsPath`, POSIX-separated (e.g. `"tilesets/ship.png"`), so the static
14
+ * route serves it at `{worldPath}/assets/files/<image>`.
15
+ *
16
+ * `tile(id)` looks up a tile by numeric id (== Phaser frame index, row-major);
17
+ * `sizeInMeters(ppm)` sizes a physics body to match the art in one call.
18
+ */
19
+ export declare class TilesetAsset extends Asset implements Tileset {
20
+ /** Resolved image path relative to `assetsPath`, POSIX-separated. */
21
+ image: string;
22
+ /** Tile width (px) — Tiled `tilewidth`. */
23
+ frameWidth: number;
24
+ /** Tile height (px) — Tiled `tileheight`. */
25
+ frameHeight: number;
26
+ /** Tileset margin (px). */
27
+ margin: number;
28
+ /** Tile spacing (px). */
29
+ spacing: number;
30
+ /** Tiles per row. */
31
+ columns: number;
32
+ /** Total frames — Tiled `tilecount`. */
33
+ tileCount: number;
34
+ /** Source image width (px) — Tiled `imagewidth`. */
35
+ imageWidth: number;
36
+ /** Source image height (px) — Tiled `imageheight`. */
37
+ imageHeight: number;
38
+ /** Tileset name. */
39
+ name: string;
40
+ /** Tileset "Class" (Tiled `class`/`type`); `""` when absent. */
41
+ class: string;
42
+ /** Typed properties, preserved as-is; `[]` when absent. */
43
+ properties: AnyProperty[];
44
+ /** Tiles keyed by numeric id (re-indexed from Tiled's sparse `tiles[]`). */
45
+ private readonly _tiles;
46
+ /**
47
+ * @param id - Server-assigned stable wire id (from `AssetManager`).
48
+ * @param key - Human authoring/debug key (filename stem).
49
+ * @param image - Resolved image path relative to `assetsPath`, POSIX.
50
+ * @param frameWidth - Tile width (px).
51
+ * @param frameHeight - Tile height (px).
52
+ * @param margin - Tileset margin (px).
53
+ * @param spacing - Tile spacing (px).
54
+ * @param columns - Tiles per row.
55
+ * @param tileCount - Total frames.
56
+ * @param imageWidth - Source image width (px).
57
+ * @param imageHeight - Source image height (px).
58
+ * @param name - Tileset name.
59
+ * @param classField - Tileset "Class" (`""` when absent).
60
+ * @param properties - Typed properties (`[]` when absent).
61
+ * @param tiles - Tiles keyed by numeric id (may be empty).
62
+ */
63
+ constructor(id: number, key: string, image: string, frameWidth: number, frameHeight: number, margin: number, spacing: number, columns: number, tileCount: number, imageWidth: number, imageHeight: number, name: string, classField: string, properties: AnyProperty[], tiles: Map<number, Tile>);
64
+ /** Look up a tile by numeric id; `undefined` when not present. */
65
+ tile(id: number): Tile | undefined;
66
+ /**
67
+ * Size a physics body to match the art: `{ w: frameWidth/ppm,
68
+ * h: frameHeight/ppm }`. PPM stays off the wire (meters everywhere).
69
+ *
70
+ * @param ppm - Pixels per meter.
71
+ * @returns `{ w, h }` in meters.
72
+ */
73
+ sizeInMeters(ppm: number): {
74
+ w: number;
75
+ h: number;
76
+ };
77
+ }
78
+ /**
79
+ * Build the `Tile` instances for a `TilesetAsset` from a raw Tiled `tiles[]`
80
+ * array, applying the non-null empty defaults for every omitted field. Used by
81
+ * the reviver to construct concrete tiles from raw input.
82
+ *
83
+ * @param rawTiles - Raw Tiled tiles array (may be undefined).
84
+ * @returns `Map<id, Tile>` keyed by numeric tile id.
85
+ */
86
+ export declare function buildTiles(rawTiles: TileRaw[] | undefined): Map<number, Tile>;
@@ -0,0 +1,102 @@
1
+ import { Asset } from "./asset.js";
2
+ import { MapObject, Tile } from "./tile.js";
3
+ /**
4
+ * Concrete `TilesetAsset` — a single-image Tiled tileset ingested as a
5
+ * spritesheet. `extends Asset` (carries `id`/`key`) and `implements` the
6
+ * vendored `Tileset` interface (no `?`): sparse Tiled fields become non-null
7
+ * empty defaults (`""`/`[]`) supplied at construction time.
8
+ *
9
+ * Field-name mapping: Tiled `tilewidth`→`frameWidth`, `tileheight`→
10
+ * `frameHeight`, `tilecount`→`tileCount`, `imagewidth`→`imageWidth`,
11
+ * `imageheight`→`imageHeight`. `image` is the resolved image path relative to
12
+ * `assetsPath`, POSIX-separated (e.g. `"tilesets/ship.png"`), so the static
13
+ * route serves it at `{worldPath}/assets/files/<image>`.
14
+ *
15
+ * `tile(id)` looks up a tile by numeric id (== Phaser frame index, row-major);
16
+ * `sizeInMeters(ppm)` sizes a physics body to match the art in one call.
17
+ */
18
+ export class TilesetAsset extends Asset {
19
+ /**
20
+ * @param id - Server-assigned stable wire id (from `AssetManager`).
21
+ * @param key - Human authoring/debug key (filename stem).
22
+ * @param image - Resolved image path relative to `assetsPath`, POSIX.
23
+ * @param frameWidth - Tile width (px).
24
+ * @param frameHeight - Tile height (px).
25
+ * @param margin - Tileset margin (px).
26
+ * @param spacing - Tile spacing (px).
27
+ * @param columns - Tiles per row.
28
+ * @param tileCount - Total frames.
29
+ * @param imageWidth - Source image width (px).
30
+ * @param imageHeight - Source image height (px).
31
+ * @param name - Tileset name.
32
+ * @param classField - Tileset "Class" (`""` when absent).
33
+ * @param properties - Typed properties (`[]` when absent).
34
+ * @param tiles - Tiles keyed by numeric id (may be empty).
35
+ */
36
+ constructor(id, key, image, frameWidth, frameHeight, margin, spacing, columns, tileCount, imageWidth, imageHeight, name, classField, properties, tiles) {
37
+ super(id, key);
38
+ this.image = image;
39
+ this.frameWidth = frameWidth;
40
+ this.frameHeight = frameHeight;
41
+ this.margin = margin;
42
+ this.spacing = spacing;
43
+ this.columns = columns;
44
+ this.tileCount = tileCount;
45
+ this.imageWidth = imageWidth;
46
+ this.imageHeight = imageHeight;
47
+ this.name = name;
48
+ this.class = classField;
49
+ this.properties = properties;
50
+ this._tiles = tiles;
51
+ }
52
+ /** Look up a tile by numeric id; `undefined` when not present. */
53
+ tile(id) {
54
+ return this._tiles.get(id);
55
+ }
56
+ /**
57
+ * Size a physics body to match the art: `{ w: frameWidth/ppm,
58
+ * h: frameHeight/ppm }`. PPM stays off the wire (meters everywhere).
59
+ *
60
+ * @param ppm - Pixels per meter.
61
+ * @returns `{ w, h }` in meters.
62
+ */
63
+ sizeInMeters(ppm) {
64
+ return { w: this.frameWidth / ppm, h: this.frameHeight / ppm };
65
+ }
66
+ }
67
+ /**
68
+ * Build the `Tile` instances for a `TilesetAsset` from a raw Tiled `tiles[]`
69
+ * array, applying the non-null empty defaults for every omitted field. Used by
70
+ * the reviver to construct concrete tiles from raw input.
71
+ *
72
+ * @param rawTiles - Raw Tiled tiles array (may be undefined).
73
+ * @returns `Map<id, Tile>` keyed by numeric tile id.
74
+ */
75
+ export function buildTiles(rawTiles) {
76
+ const map = new Map();
77
+ if (!rawTiles) {
78
+ return map;
79
+ }
80
+ for (const raw of rawTiles) {
81
+ const tile = buildTile(raw);
82
+ map.set(tile.id, tile);
83
+ }
84
+ return map;
85
+ }
86
+ /** Build a single `Tile` from raw input, applying non-null empty defaults. */
87
+ function buildTile(raw) {
88
+ return new Tile(raw.id, raw.class ?? raw.type ?? "", raw.properties ?? [], buildObjects(raw.objectgroup), raw.animation ?? []);
89
+ }
90
+ /** Build the `Map<number, MapObject>` for a tile from a raw `objectgroup`. */
91
+ function buildObjects(objectgroup) {
92
+ const map = new Map();
93
+ if (!objectgroup || !objectgroup.objects) {
94
+ return map;
95
+ }
96
+ for (const raw of objectgroup.objects) {
97
+ const obj = new MapObject(raw.id, raw.x, raw.y, raw.width ?? 0, raw.height ?? 0, raw.rotation ?? 0, raw.name ?? "", raw.type ?? "", raw.ellipse ?? false, raw.point ?? false, (raw.polygon ?? []), (raw.polyline ?? []));
98
+ map.set(obj.id, obj);
99
+ }
100
+ return map;
101
+ }
102
+ //# sourceMappingURL=tileset_asset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tileset_asset.js","sourceRoot":"","sources":["../src/tileset_asset.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Vendored Tiled schema — bare-minimum interfaces copied from `@kayahr/tiled`
3
+ * (the authoritative reference), retaining only the fields v1.0.36 uses.
4
+ *
5
+ * Two layers live here:
6
+ *
7
+ * 1. **Public interfaces** (no `?` on the v1.0.36 fields). Our concrete classes
8
+ * (`TilesetAsset`, `Tile`, `MapObject`) `implements` these, so they act as
9
+ * the type-check contract. Sparse Tiled fields become REQUIRED here, and the
10
+ * concrete classes guarantee non-null empty defaults (`[]`, empty `Map`, `""`,
11
+ * `false`, `0`) — consumers never null-check.
12
+ *
13
+ * 2. **`*Raw` interfaces** (with `?`) modeling the raw Tiled JSON the reviver
14
+ * reads. These carry the original Tiled field names (`tilewidth`, `type`,
15
+ * `objectgroup`, …) so the loader can read raw input before constructing the
16
+ * concrete tree.
17
+ *
18
+ * This file is grown field-by-field as features are added; it never depends on
19
+ * `@kayahr/tiled` at runtime or build time.
20
+ */
21
+ /**
22
+ * Tiled property type discriminant. String/file/color/class serialize as
23
+ * strings; int/float/object as numbers; bool as boolean. Color values are hex
24
+ * strings like `"#ffaa00ff"`.
25
+ */
26
+ export type PropertyType = "string" | "int" | "float" | "bool" | "color" | "file" | "object" | "class";
27
+ /**
28
+ * A single Tiled typed property. Preserved as-is (NOT flattened to a map) so
29
+ * declared types like `color`/`int`/`file` survive the round-trip.
30
+ */
31
+ export interface Property {
32
+ /** Property name. */
33
+ name: string;
34
+ /** Property type discriminant. */
35
+ type: PropertyType;
36
+ /** Value — typed by `type` (string | number | boolean). */
37
+ value: string | number | boolean;
38
+ }
39
+ /** Any Tiled property (the typed property union). */
40
+ export type AnyProperty = Property;
41
+ /** A single animation frame: `{ tileid, duration }` (ms). */
42
+ export interface Frame {
43
+ /** Tile id this frame shows. */
44
+ tileid: number;
45
+ /** Frame duration in milliseconds. */
46
+ duration: number;
47
+ }
48
+ /** A 2D point in pixels. */
49
+ export interface Point {
50
+ /** X coordinate (px). */
51
+ x: number;
52
+ /** Y coordinate (px). */
53
+ y: number;
54
+ }
55
+ /**
56
+ * Public vendored `MapObject` interface — a collision/anchor shape on a tile.
57
+ * Sparse Tiled shape flags become REQUIRED booleans/arrays defaulting to
58
+ * `false`/`[]`; a plain rectangle has none of `ellipse`/`point`/`polygon`/
59
+ * `polyline` set.
60
+ */
61
+ export interface MapObject {
62
+ /** Unique id across all objects in the tileset. */
63
+ id: number;
64
+ /** X coordinate (px). */
65
+ x: number;
66
+ /** Y coordinate (px). */
67
+ y: number;
68
+ /** Width (px); `0` when absent. */
69
+ width: number;
70
+ /** Height (px); `0` when absent. */
71
+ height: number;
72
+ /** Rotation in degrees clockwise; `0` when absent. */
73
+ rotation: number;
74
+ /** Name; `""` when absent. */
75
+ name: string;
76
+ /** Object "Class"; `""` when absent. */
77
+ type: string;
78
+ /** `true` if ellipse (a circle is an ellipse with equal dims). */
79
+ ellipse: boolean;
80
+ /** `true` if point. */
81
+ point: boolean;
82
+ /** Polygon points; `[]` when not a polygon. */
83
+ polygon: Point[];
84
+ /** Polyline points; `[]` when not a polyline. */
85
+ polyline: Point[];
86
+ }
87
+ /**
88
+ * Public vendored `Tile` interface — a single tile in a tileset. Sparse Tiled
89
+ * fields become REQUIRED with non-null empty defaults supplied by `Tile`.
90
+ */
91
+ export interface Tile {
92
+ /** Local tile id (== Phaser frame index, row-major). */
93
+ id: number;
94
+ /** Tile "Class" (Tiled `class`/`type`); `""` when absent. */
95
+ class: string;
96
+ /** Typed properties, preserved as-is; `[]` when absent. */
97
+ properties: AnyProperty[];
98
+ /** Collision/anchor shapes keyed by `MapObject.id`; empty `Map` when absent. */
99
+ objects: Map<number, MapObject>;
100
+ /** Animation frames; `[]` when absent. */
101
+ animation: Frame[];
102
+ }
103
+ /**
104
+ * Public vendored `Tileset` interface — a single-image Tiled tileset ingested
105
+ * as a spritesheet. Field names map Tiled's (`tilewidth`→`frameWidth`, etc.);
106
+ * sparse fields become REQUIRED with non-null defaults. `tile(id)` looks up a
107
+ * tile by numeric id (the concrete class re-indexes Tiled's `tiles[]` into a
108
+ * `Map`).
109
+ */
110
+ export interface Tileset {
111
+ /** Resolved image path relative to `assetsPath`, POSIX-separated. */
112
+ image: string;
113
+ /** Tile width (px) — Tiled `tilewidth`. */
114
+ frameWidth: number;
115
+ /** Tile height (px) — Tiled `tileheight`. */
116
+ frameHeight: number;
117
+ /** Tileset margin (px). */
118
+ margin: number;
119
+ /** Tile spacing (px). */
120
+ spacing: number;
121
+ /** Tiles per row. */
122
+ columns: number;
123
+ /** Total frames — Tiled `tilecount`. */
124
+ tileCount: number;
125
+ /** Source image width (px) — Tiled `imagewidth`. */
126
+ imageWidth: number;
127
+ /** Source image height (px) — Tiled `imageheight`. */
128
+ imageHeight: number;
129
+ /** Tileset name. */
130
+ name: string;
131
+ /** Tileset "Class" (Tiled `class`/`type`); `""` when absent. */
132
+ class: string;
133
+ /** Typed properties; `[]` when absent. */
134
+ properties: AnyProperty[];
135
+ /** Look up a tile by numeric id; `undefined` when not present. */
136
+ tile(id: number): Tile | undefined;
137
+ }
138
+ /** Raw `MapObject` as Tiled emits it (sparse fields optional). */
139
+ export interface MapObjectRaw {
140
+ id: number;
141
+ x: number;
142
+ y: number;
143
+ width?: number;
144
+ height?: number;
145
+ rotation?: number;
146
+ name?: string;
147
+ type?: string;
148
+ ellipse?: boolean;
149
+ point?: boolean;
150
+ polygon?: Point[];
151
+ polyline?: Point[];
152
+ }
153
+ /** Raw `Tile` as Tiled emits it (sparse fields optional; `image?` ⇒ collection). */
154
+ export interface TileRaw {
155
+ id: number;
156
+ type?: string;
157
+ class?: string;
158
+ properties?: AnyProperty[];
159
+ objectgroup?: {
160
+ objects: MapObjectRaw[];
161
+ };
162
+ animation?: Frame[];
163
+ /** Presence ⇒ image-collection tile (rejected by the scope guard). */
164
+ image?: string;
165
+ }
166
+ /** Raw `Tileset` as Tiled emits it (sparse fields optional; `image?` ⇒ collection). */
167
+ export interface TilesetRaw {
168
+ columns: number;
169
+ image?: string;
170
+ imagewidth?: number;
171
+ imageheight?: number;
172
+ margin?: number;
173
+ spacing?: number;
174
+ tilecount?: number;
175
+ tilewidth?: number;
176
+ tileheight?: number;
177
+ name?: string;
178
+ /** Tileset "Class" (Tiled >=1.9). */
179
+ class?: string;
180
+ /** Tiled file-format discriminator (`"tileset"`/`"map"`) — NOT a class. */
181
+ type?: string;
182
+ properties?: AnyProperty[];
183
+ tiles?: TileRaw[];
184
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Vendored Tiled schema — bare-minimum interfaces copied from `@kayahr/tiled`
3
+ * (the authoritative reference), retaining only the fields v1.0.36 uses.
4
+ *
5
+ * Two layers live here:
6
+ *
7
+ * 1. **Public interfaces** (no `?` on the v1.0.36 fields). Our concrete classes
8
+ * (`TilesetAsset`, `Tile`, `MapObject`) `implements` these, so they act as
9
+ * the type-check contract. Sparse Tiled fields become REQUIRED here, and the
10
+ * concrete classes guarantee non-null empty defaults (`[]`, empty `Map`, `""`,
11
+ * `false`, `0`) — consumers never null-check.
12
+ *
13
+ * 2. **`*Raw` interfaces** (with `?`) modeling the raw Tiled JSON the reviver
14
+ * reads. These carry the original Tiled field names (`tilewidth`, `type`,
15
+ * `objectgroup`, …) so the loader can read raw input before constructing the
16
+ * concrete tree.
17
+ *
18
+ * This file is grown field-by-field as features are added; it never depends on
19
+ * `@kayahr/tiled` at runtime or build time.
20
+ */
21
+ export {};
22
+ //# sourceMappingURL=tileset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tileset.js","sourceRoot":"","sources":["../../src/types/tileset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}