@codexo/exojs-ldtk 0.15.3 → 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 (67) hide show
  1. package/README.md +38 -20
  2. package/dist/esm/LdtkData.d.ts +59 -14
  3. package/dist/esm/LdtkData.d.ts.map +1 -0
  4. package/dist/esm/LdtkData.js +8 -16
  5. package/dist/esm/LdtkData.js.map +1 -1
  6. package/dist/esm/LdtkMap.d.ts +25 -6
  7. package/dist/esm/LdtkMap.d.ts.map +1 -0
  8. package/dist/esm/LdtkMap.js +88 -63
  9. package/dist/esm/LdtkMap.js.map +1 -1
  10. package/dist/esm/LdtkProject.d.ts +107 -0
  11. package/dist/esm/LdtkProject.d.ts.map +1 -0
  12. package/dist/esm/LdtkProject.js +136 -0
  13. package/dist/esm/LdtkProject.js.map +1 -0
  14. package/dist/esm/index.d.ts +1 -0
  15. package/dist/esm/index.d.ts.map +1 -0
  16. package/dist/esm/index.js +11 -7
  17. package/dist/esm/ldtkExtension.d.ts +9 -5
  18. package/dist/esm/ldtkExtension.d.ts.map +1 -0
  19. package/dist/esm/ldtkExtension.js +25 -22
  20. package/dist/esm/ldtkExtension.js.map +1 -1
  21. package/dist/esm/ldtkLevelEntries.d.ts +4 -3
  22. package/dist/esm/ldtkLevelEntries.d.ts.map +1 -0
  23. package/dist/esm/ldtkLevelEntries.js +30 -26
  24. package/dist/esm/ldtkLevelEntries.js.map +1 -1
  25. package/dist/esm/ldtkParallax.d.ts +22 -0
  26. package/dist/esm/ldtkParallax.d.ts.map +1 -0
  27. package/dist/esm/ldtkParallax.js +22 -0
  28. package/dist/esm/ldtkParallax.js.map +1 -0
  29. package/dist/esm/ldtkToMapWorld.d.ts +20 -0
  30. package/dist/esm/ldtkToMapWorld.d.ts.map +1 -0
  31. package/dist/esm/ldtkToMapWorld.js +76 -0
  32. package/dist/esm/ldtkToMapWorld.js.map +1 -0
  33. package/dist/esm/ldtkToTileMap.d.ts +48 -10
  34. package/dist/esm/ldtkToTileMap.d.ts.map +1 -0
  35. package/dist/esm/ldtkToTileMap.js +410 -387
  36. package/dist/esm/ldtkToTileMap.js.map +1 -1
  37. package/dist/esm/ldtkTypes.d.ts +47 -0
  38. package/dist/esm/ldtkTypes.d.ts.map +1 -0
  39. package/dist/esm/ldtkTypes.js +57 -0
  40. package/dist/esm/ldtkTypes.js.map +1 -0
  41. package/dist/esm/loadLdtkMap.d.ts +30 -5
  42. package/dist/esm/loadLdtkMap.d.ts.map +1 -0
  43. package/dist/esm/loadLdtkMap.js +139 -133
  44. package/dist/esm/loadLdtkMap.js.map +1 -1
  45. package/dist/esm/loadLdtkProject.d.ts +17 -0
  46. package/dist/esm/loadLdtkProject.d.ts.map +1 -0
  47. package/dist/esm/loadLdtkProject.js +31 -0
  48. package/dist/esm/loadLdtkProject.js.map +1 -0
  49. package/dist/esm/public.d.ts +24 -9
  50. package/dist/esm/public.d.ts.map +1 -0
  51. package/dist/esm/public.js +11 -0
  52. package/dist/esm/url.d.ts +16 -0
  53. package/dist/esm/url.d.ts.map +1 -0
  54. package/dist/esm/url.js +31 -0
  55. package/dist/esm/url.js.map +1 -0
  56. package/dist/esm/validate.d.ts +27 -0
  57. package/dist/esm/validate.d.ts.map +1 -0
  58. package/dist/esm/validate.js +327 -0
  59. package/dist/esm/validate.js.map +1 -0
  60. package/package.json +10 -18
  61. package/dist/esm/index.js.map +0 -1
  62. package/dist/esm/ldtkBinding.d.ts +0 -22
  63. package/dist/esm/ldtkBinding.js +0 -31
  64. package/dist/esm/ldtkBinding.js.map +0 -1
  65. package/dist/esm/register.d.ts +0 -1
  66. package/dist/esm/register.js +0 -17
  67. package/dist/esm/register.js.map +0 -1
@@ -0,0 +1,107 @@
1
+ import type { LoaderScope } from '@codexo/exojs';
2
+ import type { MapWorld, TileSet } from '@codexo/exojs-tilemap';
3
+ import { MapWorldRuntime } from '@codexo/exojs-tilemap';
4
+ import type { LdtkData } from './LdtkData';
5
+ /** Options for {@link LdtkProject.createRuntime}. */
6
+ export interface LdtkRuntimeOptions {
7
+ /**
8
+ * Parent scope for everything the runtime loads. The runtime creates its own
9
+ * child scope under it and never destroys this one.
10
+ */
11
+ readonly scope: LoaderScope;
12
+ /**
13
+ * Which world of a multi-world project to stream, by identifier. Defaults to
14
+ * the first world in document order, which is the only one a single-world
15
+ * project has.
16
+ */
17
+ readonly world?: string;
18
+ }
19
+ /**
20
+ * A loaded LDtk project, prepared for streaming: world layout and tileset
21
+ * atlases are resident, level payloads are not.
22
+ *
23
+ * This is the entry point for a game that loads levels as it needs them. Read
24
+ * {@link worlds} to decide what to load, then drive a
25
+ * {@link MapWorldRuntime} from {@link createRuntime} to load and unload
26
+ * individual levels, each with its own asset scope.
27
+ *
28
+ * What is eager, and why:
29
+ *
30
+ * - the `.ldtk` document itself, because the world layout is what the game
31
+ * navigates by;
32
+ * - every tileset atlas. This is a prefetch policy, not a technical
33
+ * requirement, and it is bounded: LDtk declares tilesets once per project
34
+ * (`defs.tilesets`), never per level, so the count does not grow with the
35
+ * number of levels. Paying for them once keeps a level load off the network
36
+ * entirely for a non-externalized project, and off the *image* network for an
37
+ * externalized one.
38
+ *
39
+ * The atlases are claimed by this asset's own scope, so their residency is tied
40
+ * to how long the `ldtkProject` asset is held - not to a
41
+ * {@link MapWorldRuntime}. Releasing the asset releases them; destroying a
42
+ * runtime does not.
43
+ *
44
+ * What is lazy:
45
+ *
46
+ * - external `.ldtkl` level payloads - fetched when the level loads, claimed
47
+ * by that level's scope, released when it unloads;
48
+ * - the conversion of a level into a runtime `TileMap`;
49
+ * - anything the level's {@link import('@codexo/exojs-tilemap').MapObjectSpawner} creates.
50
+ *
51
+ * Load the whole project at once with the `ldtkMap` asset type instead
52
+ * ({@link import('./LdtkMap').LdtkMap}) when a game is small enough not to
53
+ * need any of this.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const project = await scene.loader.load(Asset.type('ldtkProject', 'world.ldtk'));
58
+ * const runtime = project.createRuntime({ scope: scene.loader });
59
+ *
60
+ * const forest = await runtime.loadLevel(project.world.getLevelByName('Forest')!.id, {
61
+ * spawner,
62
+ * context: { services, save },
63
+ * });
64
+ *
65
+ * scene.addChild(forest.map.createView().root);
66
+ * runtime.unloadLevel(forest.id);
67
+ * ```
68
+ */
69
+ export declare class LdtkProject {
70
+ /** Resolved URL this project was loaded from. */
71
+ readonly source: string;
72
+ /** The raw parsed LDtk document. Externalized levels still carry `layerInstances: null`. */
73
+ readonly data: LdtkData;
74
+ /** Runtime tilesets keyed by LDtk tileset uid, shared by every level of the project. */
75
+ readonly tilesets: ReadonlyMap<number, TileSet>;
76
+ /** World layout, one entry per LDtk world. See {@link import('./ldtkToMapWorld').ldtkToMapWorld}. */
77
+ readonly worlds: readonly MapWorld[];
78
+ private readonly _entries;
79
+ /** Projects are produced by the `ldtkProject` asset binding. @internal */
80
+ constructor(source: string, data: LdtkData, tilesets: ReadonlyMap<number, TileSet>);
81
+ /**
82
+ * The project's only world. For a multi-world project this is the first in
83
+ * document order; read {@link worlds} to reach the others.
84
+ */
85
+ get world(): MapWorld;
86
+ /** The world with this identifier, or `undefined`. */
87
+ getWorld(name: string): MapWorld | undefined;
88
+ /**
89
+ * Create the live runtime that loads and unloads this project's levels.
90
+ *
91
+ * The runtime is a separate lifetime from the project: destroying it unloads
92
+ * every level it holds and leaves the project - document, world layout and
93
+ * tilesets - intact, ready for a new runtime.
94
+ *
95
+ * @throws {Error} when `options.world` names no world of this project.
96
+ */
97
+ createRuntime(options: LdtkRuntimeOptions): MapWorldRuntime;
98
+ private _loadLevel;
99
+ /**
100
+ * Fetch an externalized level's `.ldtkl` payload and merge it into the level
101
+ * record. The fetch is claimed by the level's own scope, so it is released
102
+ * when the level unloads and re-fetched (or served from the loader's cache)
103
+ * on a later load.
104
+ */
105
+ private _resolveLevel;
106
+ }
107
+ //# sourceMappingURL=LdtkProject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LdtkProject.d.ts","sourceRoot":"","sources":["../../src/LdtkProject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAuB,QAAQ,EAAW,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,YAAY,CAAC;AAQtD,qDAAqD;AACrD,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,WAAW;IACtB,iDAAiD;IACjD,SAAgB,MAAM,EAAE,MAAM,CAAC;IAC/B,4FAA4F;IAC5F,SAAgB,IAAI,EAAE,QAAQ,CAAC;IAC/B,wFAAwF;IACxF,SAAgB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,qGAAqG;IACrG,SAAgB,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IAE5C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IAErD,0EAA0E;gBACvD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAQzF;;;OAGG;IACH,IAAW,KAAK,IAAI,QAAQ,CAQ3B;IAED,sDAAsD;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAInD;;;;;;;;OAQG;IACI,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,eAAe;YAcpD,UAAU;IAYxB;;;;;OAKG;YACW,aAAa;CAiB5B"}
@@ -0,0 +1,136 @@
1
+ import { getLdtkLevelEntries } from "./ldtkLevelEntries.js";
2
+ import { ldtkLevelToTileMap } from "./ldtkToTileMap.js";
3
+ import { ldtkToMapWorld } from "./ldtkToMapWorld.js";
4
+ import { resolveLdtkUrl } from "./url.js";
5
+ import { validateLdtkLevelData } from "./validate.js";
6
+ import { MapWorldRuntime } from "@codexo/exojs-tilemap";
7
+ import { Asset } from "@codexo/exojs";
8
+
9
+ //#region src/LdtkProject.ts
10
+ /**
11
+ * A loaded LDtk project, prepared for streaming: world layout and tileset
12
+ * atlases are resident, level payloads are not.
13
+ *
14
+ * This is the entry point for a game that loads levels as it needs them. Read
15
+ * {@link worlds} to decide what to load, then drive a
16
+ * {@link MapWorldRuntime} from {@link createRuntime} to load and unload
17
+ * individual levels, each with its own asset scope.
18
+ *
19
+ * What is eager, and why:
20
+ *
21
+ * - the `.ldtk` document itself, because the world layout is what the game
22
+ * navigates by;
23
+ * - every tileset atlas. This is a prefetch policy, not a technical
24
+ * requirement, and it is bounded: LDtk declares tilesets once per project
25
+ * (`defs.tilesets`), never per level, so the count does not grow with the
26
+ * number of levels. Paying for them once keeps a level load off the network
27
+ * entirely for a non-externalized project, and off the *image* network for an
28
+ * externalized one.
29
+ *
30
+ * The atlases are claimed by this asset's own scope, so their residency is tied
31
+ * to how long the `ldtkProject` asset is held - not to a
32
+ * {@link MapWorldRuntime}. Releasing the asset releases them; destroying a
33
+ * runtime does not.
34
+ *
35
+ * What is lazy:
36
+ *
37
+ * - external `.ldtkl` level payloads - fetched when the level loads, claimed
38
+ * by that level's scope, released when it unloads;
39
+ * - the conversion of a level into a runtime `TileMap`;
40
+ * - anything the level's {@link import('@codexo/exojs-tilemap').MapObjectSpawner} creates.
41
+ *
42
+ * Load the whole project at once with the `ldtkMap` asset type instead
43
+ * ({@link import('./LdtkMap').LdtkMap}) when a game is small enough not to
44
+ * need any of this.
45
+ *
46
+ * @example
47
+ * ```ts
48
+ * const project = await scene.loader.load(Asset.type('ldtkProject', 'world.ldtk'));
49
+ * const runtime = project.createRuntime({ scope: scene.loader });
50
+ *
51
+ * const forest = await runtime.loadLevel(project.world.getLevelByName('Forest')!.id, {
52
+ * spawner,
53
+ * context: { services, save },
54
+ * });
55
+ *
56
+ * scene.addChild(forest.map.createView().root);
57
+ * runtime.unloadLevel(forest.id);
58
+ * ```
59
+ */
60
+ var LdtkProject = class {
61
+ /** Resolved URL this project was loaded from. */
62
+ source;
63
+ /** The raw parsed LDtk document. Externalized levels still carry `layerInstances: null`. */
64
+ data;
65
+ /** Runtime tilesets keyed by LDtk tileset uid, shared by every level of the project. */
66
+ tilesets;
67
+ /** World layout, one entry per LDtk world. See {@link import('./ldtkToMapWorld').ldtkToMapWorld}. */
68
+ worlds;
69
+ _entries;
70
+ /** Projects are produced by the `ldtkProject` asset binding. @internal */
71
+ constructor(source, data, tilesets) {
72
+ this.source = source;
73
+ this.data = data;
74
+ this.tilesets = tilesets;
75
+ this.worlds = ldtkToMapWorld(data);
76
+ this._entries = getLdtkLevelEntries(data);
77
+ }
78
+ /**
79
+ * The project's only world. For a multi-world project this is the first in
80
+ * document order; read {@link worlds} to reach the others.
81
+ */
82
+ get world() {
83
+ const [first] = this.worlds;
84
+ if (first === void 0) throw new Error(`LdtkProject: "${this.source}" declares no world.`);
85
+ return first;
86
+ }
87
+ /** The world with this identifier, or `undefined`. */
88
+ getWorld(name) {
89
+ return this.worlds.find((world) => world.name === name);
90
+ }
91
+ /**
92
+ * Create the live runtime that loads and unloads this project's levels.
93
+ *
94
+ * The runtime is a separate lifetime from the project: destroying it unloads
95
+ * every level it holds and leaves the project - document, world layout and
96
+ * tilesets - intact, ready for a new runtime.
97
+ *
98
+ * @throws {Error} when `options.world` names no world of this project.
99
+ */
100
+ createRuntime(options) {
101
+ const world = options.world === void 0 ? this.world : this.getWorld(options.world);
102
+ if (world === void 0) throw new Error(`LdtkProject: "${this.source}" has no world named "${options.world ?? ""}".`);
103
+ return new MapWorldRuntime({
104
+ world,
105
+ scope: options.scope,
106
+ load: (context) => this._loadLevel(context)
107
+ });
108
+ }
109
+ async _loadLevel(context) {
110
+ const entry = this._entries[context.level.index];
111
+ if (entry === void 0) throw new Error(`LdtkProject: level "${context.level.id}" has index ${context.level.index}, which is outside "${this.source}".`);
112
+ const level = await this._resolveLevel(entry.level, context.scope);
113
+ return ldtkLevelToTileMap(level, entry.worldIid, context.level.index, this.data, this.tilesets);
114
+ }
115
+ /**
116
+ * Fetch an externalized level's `.ldtkl` payload and merge it into the level
117
+ * record. The fetch is claimed by the level's own scope, so it is released
118
+ * when the level unloads and re-fetched (or served from the loader's cache)
119
+ * on a later load.
120
+ */
121
+ async _resolveLevel(level, scope) {
122
+ if (level.layerInstances !== null || level.externalRelPath === void 0 || level.externalRelPath === null || level.externalRelPath === "") return level;
123
+ const url = resolveLdtkUrl(level.externalRelPath, this.source);
124
+ const external = validateLdtkLevelData(await scope.load(Asset.type("json", url)), url);
125
+ const fieldInstances = external.fieldInstances ?? level.fieldInstances;
126
+ return {
127
+ ...level,
128
+ layerInstances: external.layerInstances,
129
+ ...fieldInstances !== void 0 && { fieldInstances }
130
+ };
131
+ }
132
+ };
133
+
134
+ //#endregion
135
+ export { LdtkProject };
136
+ //# sourceMappingURL=LdtkProject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LdtkProject.js","names":[],"sources":["../../src/LdtkProject.ts"],"sourcesContent":["import type { LoaderScope } from '@codexo/exojs';\nimport { Asset } from '@codexo/exojs';\nimport type { MapLevelLoadContext, MapWorld, TileMap, TileSet } from '@codexo/exojs-tilemap';\nimport { MapWorldRuntime } from '@codexo/exojs-tilemap';\n\nimport type { LdtkData, LdtkLevel } from './LdtkData';\nimport type { LdtkLevelEntry } from './ldtkLevelEntries';\nimport { getLdtkLevelEntries } from './ldtkLevelEntries';\nimport { ldtkToMapWorld } from './ldtkToMapWorld';\nimport { ldtkLevelToTileMap } from './ldtkToTileMap';\nimport { resolveLdtkUrl } from './url';\nimport { validateLdtkLevelData } from './validate';\n\n/** Options for {@link LdtkProject.createRuntime}. */\nexport interface LdtkRuntimeOptions {\n /**\n * Parent scope for everything the runtime loads. The runtime creates its own\n * child scope under it and never destroys this one.\n */\n readonly scope: LoaderScope;\n /**\n * Which world of a multi-world project to stream, by identifier. Defaults to\n * the first world in document order, which is the only one a single-world\n * project has.\n */\n readonly world?: string;\n}\n\n/**\n * A loaded LDtk project, prepared for streaming: world layout and tileset\n * atlases are resident, level payloads are not.\n *\n * This is the entry point for a game that loads levels as it needs them. Read\n * {@link worlds} to decide what to load, then drive a\n * {@link MapWorldRuntime} from {@link createRuntime} to load and unload\n * individual levels, each with its own asset scope.\n *\n * What is eager, and why:\n *\n * - the `.ldtk` document itself, because the world layout is what the game\n * navigates by;\n * - every tileset atlas. This is a prefetch policy, not a technical\n * requirement, and it is bounded: LDtk declares tilesets once per project\n * (`defs.tilesets`), never per level, so the count does not grow with the\n * number of levels. Paying for them once keeps a level load off the network\n * entirely for a non-externalized project, and off the *image* network for an\n * externalized one.\n *\n * The atlases are claimed by this asset's own scope, so their residency is tied\n * to how long the `ldtkProject` asset is held - not to a\n * {@link MapWorldRuntime}. Releasing the asset releases them; destroying a\n * runtime does not.\n *\n * What is lazy:\n *\n * - external `.ldtkl` level payloads - fetched when the level loads, claimed\n * by that level's scope, released when it unloads;\n * - the conversion of a level into a runtime `TileMap`;\n * - anything the level's {@link import('@codexo/exojs-tilemap').MapObjectSpawner} creates.\n *\n * Load the whole project at once with the `ldtkMap` asset type instead\n * ({@link import('./LdtkMap').LdtkMap}) when a game is small enough not to\n * need any of this.\n *\n * @example\n * ```ts\n * const project = await scene.loader.load(Asset.type('ldtkProject', 'world.ldtk'));\n * const runtime = project.createRuntime({ scope: scene.loader });\n *\n * const forest = await runtime.loadLevel(project.world.getLevelByName('Forest')!.id, {\n * spawner,\n * context: { services, save },\n * });\n *\n * scene.addChild(forest.map.createView().root);\n * runtime.unloadLevel(forest.id);\n * ```\n */\nexport class LdtkProject {\n /** Resolved URL this project was loaded from. */\n public readonly source: string;\n /** The raw parsed LDtk document. Externalized levels still carry `layerInstances: null`. */\n public readonly data: LdtkData;\n /** Runtime tilesets keyed by LDtk tileset uid, shared by every level of the project. */\n public readonly tilesets: ReadonlyMap<number, TileSet>;\n /** World layout, one entry per LDtk world. See {@link import('./ldtkToMapWorld').ldtkToMapWorld}. */\n public readonly worlds: readonly MapWorld[];\n\n private readonly _entries: readonly LdtkLevelEntry[];\n\n /** Projects are produced by the `ldtkProject` asset binding. @internal */\n public constructor(source: string, data: LdtkData, tilesets: ReadonlyMap<number, TileSet>) {\n this.source = source;\n this.data = data;\n this.tilesets = tilesets;\n this.worlds = ldtkToMapWorld(data);\n this._entries = getLdtkLevelEntries(data);\n }\n\n /**\n * The project's only world. For a multi-world project this is the first in\n * document order; read {@link worlds} to reach the others.\n */\n public get world(): MapWorld {\n const [first] = this.worlds;\n\n if (first === undefined) {\n throw new Error(`LdtkProject: \"${this.source}\" declares no world.`);\n }\n\n return first;\n }\n\n /** The world with this identifier, or `undefined`. */\n public getWorld(name: string): MapWorld | undefined {\n return this.worlds.find(world => world.name === name);\n }\n\n /**\n * Create the live runtime that loads and unloads this project's levels.\n *\n * The runtime is a separate lifetime from the project: destroying it unloads\n * every level it holds and leaves the project - document, world layout and\n * tilesets - intact, ready for a new runtime.\n *\n * @throws {Error} when `options.world` names no world of this project.\n */\n public createRuntime(options: LdtkRuntimeOptions): MapWorldRuntime {\n const world = options.world === undefined ? this.world : this.getWorld(options.world);\n\n if (world === undefined) {\n throw new Error(`LdtkProject: \"${this.source}\" has no world named \"${options.world ?? ''}\".`);\n }\n\n return new MapWorldRuntime({\n world,\n scope: options.scope,\n load: context => this._loadLevel(context),\n });\n }\n\n private async _loadLevel(context: MapLevelLoadContext): Promise<TileMap> {\n const entry = this._entries[context.level.index];\n\n if (entry === undefined) {\n throw new Error(`LdtkProject: level \"${context.level.id}\" has index ${context.level.index}, which is outside \"${this.source}\".`);\n }\n\n const level = await this._resolveLevel(entry.level, context.scope);\n\n return ldtkLevelToTileMap(level, entry.worldIid, context.level.index, this.data, this.tilesets);\n }\n\n /**\n * Fetch an externalized level's `.ldtkl` payload and merge it into the level\n * record. The fetch is claimed by the level's own scope, so it is released\n * when the level unloads and re-fetched (or served from the loader's cache)\n * on a later load.\n */\n private async _resolveLevel(level: LdtkLevel, scope: LoaderScope): Promise<LdtkLevel> {\n if (level.layerInstances !== null || level.externalRelPath === undefined || level.externalRelPath === null || level.externalRelPath === '') {\n return level;\n }\n\n const url = resolveLdtkUrl(level.externalRelPath, this.source);\n // Validated as strictly as an inlined level, with the `.ldtkl` file as the\n // error source - a malformed external payload must fail as loudly.\n const external = validateLdtkLevelData(await scope.load(Asset.type('json', url)), url);\n const fieldInstances = external.fieldInstances ?? level.fieldInstances;\n\n return {\n ...level,\n layerInstances: external.layerInstances,\n ...(fieldInstances !== undefined && { fieldInstances }),\n };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8EA,IAAa,cAAb,MAAyB;;CAEvB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;;CAEhB,AAAgB;CAEhB,AAAiB;;CAGjB,AAAO,YAAY,QAAgB,MAAgB,UAAwC;EACzF,KAAK,SAAS;EACd,KAAK,OAAO;EACZ,KAAK,WAAW;EAChB,KAAK,SAAS,eAAe,IAAI;EACjC,KAAK,WAAW,oBAAoB,IAAI;CAC1C;;;;;CAMA,IAAW,QAAkB;EAC3B,MAAM,CAAC,SAAS,KAAK;EAErB,IAAI,UAAU,QACZ,MAAM,IAAI,MAAM,iBAAiB,KAAK,OAAO,qBAAqB;EAGpE,OAAO;CACT;;CAGA,AAAO,SAAS,MAAoC;EAClD,OAAO,KAAK,OAAO,MAAK,UAAS,MAAM,SAAS,IAAI;CACtD;;;;;;;;;;CAWA,AAAO,cAAc,SAA8C;EACjE,MAAM,QAAQ,QAAQ,UAAU,SAAY,KAAK,QAAQ,KAAK,SAAS,QAAQ,KAAK;EAEpF,IAAI,UAAU,QACZ,MAAM,IAAI,MAAM,iBAAiB,KAAK,OAAO,wBAAwB,QAAQ,SAAS,GAAG,GAAG;EAG9F,OAAO,IAAI,gBAAgB;GACzB;GACA,OAAO,QAAQ;GACf,OAAM,YAAW,KAAK,WAAW,OAAO;EAC1C,CAAC;CACH;CAEA,MAAc,WAAW,SAAgD;EACvE,MAAM,QAAQ,KAAK,SAAS,QAAQ,MAAM;EAE1C,IAAI,UAAU,QACZ,MAAM,IAAI,MAAM,uBAAuB,QAAQ,MAAM,GAAG,cAAc,QAAQ,MAAM,MAAM,sBAAsB,KAAK,OAAO,GAAG;EAGjI,MAAM,QAAQ,MAAM,KAAK,cAAc,MAAM,OAAO,QAAQ,KAAK;EAEjE,OAAO,mBAAmB,OAAO,MAAM,UAAU,QAAQ,MAAM,OAAO,KAAK,MAAM,KAAK,QAAQ;CAChG;;;;;;;CAQA,MAAc,cAAc,OAAkB,OAAwC;EACpF,IAAI,MAAM,mBAAmB,QAAQ,MAAM,oBAAoB,UAAa,MAAM,oBAAoB,QAAQ,MAAM,oBAAoB,IACtI,OAAO;EAGT,MAAM,MAAM,eAAe,MAAM,iBAAiB,KAAK,MAAM;EAG7D,MAAM,WAAW,sBAAsB,MAAM,MAAM,KAAK,MAAM,KAAK,QAAQ,GAAG,CAAC,GAAG,GAAG;EACrF,MAAM,iBAAiB,SAAS,kBAAkB,MAAM;EAExD,OAAO;GACL,GAAG;GACH,gBAAgB,SAAS;GACzB,GAAI,mBAAmB,UAAa,EAAE,eAAe;EACvD;CACF;AACF"}
@@ -1 +1,2 @@
1
1
  export * from './public';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,cAAc,UAAU,CAAC"}
package/dist/esm/index.js CHANGED
@@ -1,7 +1,11 @@
1
- export { ldtkMapBinding } from './ldtkBinding.js';
2
- export { ldtkExtension } from './ldtkExtension.js';
3
- export { LdtkMap } from './LdtkMap.js';
4
- export { getLdtkIntGridValueAt, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkToTileMap } from './ldtkToTileMap.js';
5
- export { ldtkFlipNone, ldtkFlipX, ldtkFlipXy, ldtkFlipY } from './LdtkData.js';
6
- export { ObjectKind, ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer, TileMap, TileMapView, TilePropertyKind, TileSet, tilemapExtension } from '@codexo/exojs-tilemap';
7
- //# sourceMappingURL=index.js.map
1
+ import { LDTK_FLIP_NONE, LDTK_FLIP_X, LDTK_FLIP_XY, LDTK_FLIP_Y } from "./LdtkData.js";
2
+ import { createLdtkIntGridCellSource, getLdtkIntGridValueAt, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkToTileMap } from "./ldtkToTileMap.js";
3
+ import { ldtkToMapWorld } from "./ldtkToMapWorld.js";
4
+ import { LdtkMap } from "./LdtkMap.js";
5
+ import { LdtkFormatError } from "./validate.js";
6
+ import { LdtkProject } from "./LdtkProject.js";
7
+ import { LdtkMapAssetType, LdtkProjectAssetType, ldtkMapType, ldtkProjectType } from "./ldtkTypes.js";
8
+ import { ldtkExtension } from "./ldtkExtension.js";
9
+ import { MapLevelRuntime, MapLevelSide, MapObjectSpawner, MapSpawnError, MapSpawnSession, MapWorld, MapWorldRuntime, ObjectKind, ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer, TileMap, TileMapView, TilePropertyKind, TileSet, mapObjectDescriptor, mapObjectDescriptors, tilemapExtension } from "./public.js";
10
+
11
+ export { LDTK_FLIP_NONE, LDTK_FLIP_X, LDTK_FLIP_XY, LDTK_FLIP_Y, LdtkFormatError, LdtkMap, LdtkMapAssetType, LdtkProject, LdtkProjectAssetType, MapLevelRuntime, MapLevelSide, MapObjectSpawner, MapSpawnError, MapSpawnSession, MapWorld, MapWorldRuntime, ObjectKind, ObjectLayer, TILE_TRANSFORM_IDENTITY, TileLayer, TileMap, TileMapView, TilePropertyKind, TileSet, createLdtkIntGridCellSource, getLdtkIntGridValueAt, ldtkExtension, ldtkIntGridCsvProperty, ldtkIntGridValuesProperty, ldtkMapType, ldtkProjectType, ldtkToMapWorld, ldtkToTileMap, mapObjectDescriptor, mapObjectDescriptors, tilemapExtension };
@@ -2,16 +2,20 @@ import type { Extension } from '@codexo/exojs/extensions';
2
2
  /**
3
3
  * Default immutable LDtk extension descriptor.
4
4
  *
5
- * Registers one asset binding:
6
- * - {@link ldtkMapBinding} `loader.load(LdtkMap, 'world.ldtk')` → fetches
7
- * the `.ldtk` JSON, loads all referenced tileset images, and returns a
5
+ * Installs two asset types:
6
+ * - {@link ldtkMapType} - `loader.load(ldtkMapType.asset('world.ldtk'))` reads
7
+ * the `.ldtk` document, loads all referenced tileset images, and returns a
8
8
  * fully assembled {@link LdtkMap} with one runtime
9
9
  * {@link import('@codexo/exojs-tilemap').TileMap} per level.
10
+ * - {@link ldtkProjectType} - `loader.load(ldtkProjectType.asset('world.ldtk'))`
11
+ * returns the world layout and tileset atlases only, for games that load
12
+ * levels on demand.
10
13
  *
11
14
  * Depends on {@link tilemapExtension} so that snapshot construction always
12
15
  * materialises the generic tilemap runtime before the LDtk adapter.
13
16
  *
14
- * Use with `ApplicationOptions.extensions` or call
15
- * `import '@codexo/exojs-ldtk/register'` for global auto-registration.
17
+ * Pass it to the application that should have it via
18
+ * `ApplicationOptions.extensions`.
16
19
  */
17
20
  export declare const ldtkExtension: Extension;
21
+ //# sourceMappingURL=ldtkExtension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ldtkExtension.d.ts","sourceRoot":"","sources":["../../src/ldtkExtension.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAK1D;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,aAAa,EAAE,SAI1B,CAAC"}
@@ -1,28 +1,31 @@
1
- import { tilemapExtension } from '@codexo/exojs-tilemap';
2
- import { ldtkMapBinding } from './ldtkBinding.js';
1
+ import { ldtkMapType, ldtkProjectType } from "./ldtkTypes.js";
2
+ import { tilemapExtension } from "@codexo/exojs-tilemap";
3
3
 
4
+ //#region src/ldtkExtension.ts
4
5
  /**
5
- * Default immutable LDtk extension descriptor.
6
- *
7
- * Registers one asset binding:
8
- * - {@link ldtkMapBinding} `loader.load(LdtkMap, 'world.ldtk')` → fetches
9
- * the `.ldtk` JSON, loads all referenced tileset images, and returns a
10
- * fully assembled {@link LdtkMap} with one runtime
11
- * {@link import('@codexo/exojs-tilemap').TileMap} per level.
12
- *
13
- * Depends on {@link tilemapExtension} so that snapshot construction always
14
- * materialises the generic tilemap runtime before the LDtk adapter.
15
- *
16
- * Use with `ApplicationOptions.extensions` or call
17
- * `import '@codexo/exojs-ldtk/register'` for global auto-registration.
18
- */
6
+ * Default immutable LDtk extension descriptor.
7
+ *
8
+ * Installs two asset types:
9
+ * - {@link ldtkMapType} - `loader.load(ldtkMapType.asset('world.ldtk'))` reads
10
+ * the `.ldtk` document, loads all referenced tileset images, and returns a
11
+ * fully assembled {@link LdtkMap} with one runtime
12
+ * {@link import('@codexo/exojs-tilemap').TileMap} per level.
13
+ * - {@link ldtkProjectType} - `loader.load(ldtkProjectType.asset('world.ldtk'))`
14
+ * returns the world layout and tileset atlases only, for games that load
15
+ * levels on demand.
16
+ *
17
+ * Depends on {@link tilemapExtension} so that snapshot construction always
18
+ * materialises the generic tilemap runtime before the LDtk adapter.
19
+ *
20
+ * Pass it to the application that should have it via
21
+ * `ApplicationOptions.extensions`.
22
+ */
19
23
  const ldtkExtension = Object.freeze({
20
- id: '@codexo/exojs-ldtk',
21
- dependencies: [tilemapExtension],
22
- // Localized erasure cast: typed binding meets the untyped Extension.assets
23
- // contract here. Runtime behaviour is unaffected.
24
- assets: [ldtkMapBinding],
24
+ id: "@codexo/exojs-ldtk",
25
+ dependencies: [tilemapExtension],
26
+ assets: [ldtkMapType, ldtkProjectType]
25
27
  });
26
28
 
29
+ //#endregion
27
30
  export { ldtkExtension };
28
- //# sourceMappingURL=ldtkExtension.js.map
31
+ //# sourceMappingURL=ldtkExtension.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ldtkExtension.js","sources":["../../../src/ldtkExtension.ts"],"sourcesContent":[null],"names":[],"mappings":";;;AAKA;;;;;;;;;;;;;;AAcG;AACI,MAAM,aAAa,GAAc,MAAM,CAAC,MAAM,CAAC;AACpD,IAAA,EAAE,EAAE,oBAAoB;IACxB,YAAY,EAAE,CAAC,gBAAgB,CAAC;;;IAGhC,MAAM,EAAE,CAAC,cAAc,CAA8B;AACtD,CAAA;;;;"}
1
+ {"version":3,"file":"ldtkExtension.js","names":[],"sources":["../../src/ldtkExtension.ts"],"sourcesContent":["import type { Extension } from '@codexo/exojs/extensions';\nimport { tilemapExtension } from '@codexo/exojs-tilemap';\n\nimport { ldtkMapType, ldtkProjectType } from './ldtkTypes';\n\n/**\n * Default immutable LDtk extension descriptor.\n *\n * Installs two asset types:\n * - {@link ldtkMapType} - `loader.load(ldtkMapType.asset('world.ldtk'))` reads\n * the `.ldtk` document, loads all referenced tileset images, and returns a\n * fully assembled {@link LdtkMap} with one runtime\n * {@link import('@codexo/exojs-tilemap').TileMap} per level.\n * - {@link ldtkProjectType} - `loader.load(ldtkProjectType.asset('world.ldtk'))`\n * returns the world layout and tileset atlases only, for games that load\n * levels on demand.\n *\n * Depends on {@link tilemapExtension} so that snapshot construction always\n * materialises the generic tilemap runtime before the LDtk adapter.\n *\n * Pass it to the application that should have it via\n * `ApplicationOptions.extensions`.\n */\nexport const ldtkExtension: Extension = Object.freeze({\n id: '@codexo/exojs-ldtk',\n dependencies: [tilemapExtension],\n assets: [ldtkMapType, ldtkProjectType],\n});\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,gBAA2B,OAAO,OAAO;CACpD,IAAI;CACJ,cAAc,CAAC,gBAAgB;CAC/B,QAAQ,CAAC,aAAa,eAAe;AACvC,CAAC"}
@@ -3,7 +3,7 @@ import type { LdtkData, LdtkLevel } from './LdtkData';
3
3
  * One level from a (possibly multi-world) {@link LdtkData} document, paired
4
4
  * with the {@link import('./LdtkData').LdtkWorldData.iid} of the world it
5
5
  * belongs to. `worldIid` is `undefined` when the document uses the legacy
6
- * single-world shape (`data.levels`, no `worlds[]`) the overwhelmingly
6
+ * single-world shape (`data.levels`, no `worlds[]`) - the overwhelmingly
7
7
  * common case.
8
8
  */
9
9
  export interface LdtkLevelEntry {
@@ -17,11 +17,12 @@ export interface LdtkLevelEntry {
17
17
  * `data.worlds[].levels`, each tagged here with its owning world's `iid`;
18
18
  * per the LDtk spec the root `levels` array is kept but EMPTY in this shape).
19
19
  *
20
- * This is the single place that decides which shape a document uses every
20
+ * This is the single place that decides which shape a document uses - every
21
21
  * consumer that needs "all levels, in document order" ({@link import('./loadLdtkMap').loadLdtkMap}'s
22
22
  * external `.ldtkl` resolution, {@link import('./ldtkToTileMap').ldtkToTileMap}'s
23
23
  * conversion, and {@link import('./LdtkMap').LdtkMap.getLevelByName}'s lookup)
24
24
  * goes through this function rather than re-deriving the single/multi-world
25
25
  * detection independently.
26
26
  */
27
- export declare function getLdtkLevelEntries(data: LdtkData): readonly LdtkLevelEntry[];
27
+ export declare const getLdtkLevelEntries: (data: LdtkData) => readonly LdtkLevelEntry[];
28
+ //# sourceMappingURL=ldtkLevelEntries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ldtkLevelEntries.d.ts","sourceRoot":"","sources":["../../src/ldtkLevelEntries.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,QAAQ,KAAG,SAAS,cAAc,EAY3E,CAAC"}
@@ -1,29 +1,33 @@
1
+ //#region src/ldtkLevelEntries.ts
1
2
  /**
2
- * Flatten a {@link LdtkData} document's levels into one ordered list,
3
- * abstracting over LDtk's two root shapes: single-world (levels live in the
4
- * root {@link LdtkData.levels}) and multi-world (levels live in
5
- * `data.worlds[].levels`, each tagged here with its owning world's `iid`;
6
- * per the LDtk spec the root `levels` array is kept but EMPTY in this shape).
7
- *
8
- * This is the single place that decides which shape a document uses every
9
- * consumer that needs "all levels, in document order" ({@link import('./loadLdtkMap').loadLdtkMap}'s
10
- * external `.ldtkl` resolution, {@link import('./ldtkToTileMap').ldtkToTileMap}'s
11
- * conversion, and {@link import('./LdtkMap').LdtkMap.getLevelByName}'s lookup)
12
- * goes through this function rather than re-deriving the single/multi-world
13
- * detection independently.
14
- */
15
- function getLdtkLevelEntries(data) {
16
- if (data.worlds && data.worlds.length > 0) {
17
- const entries = [];
18
- for (const world of data.worlds) {
19
- for (const level of world.levels) {
20
- entries.push({ level, worldIid: world.iid });
21
- }
22
- }
23
- return entries;
24
- }
25
- return data.levels.map(level => ({ level, worldIid: undefined }));
26
- }
3
+ * Flatten a {@link LdtkData} document's levels into one ordered list,
4
+ * abstracting over LDtk's two root shapes: single-world (levels live in the
5
+ * root {@link LdtkData.levels}) and multi-world (levels live in
6
+ * `data.worlds[].levels`, each tagged here with its owning world's `iid`;
7
+ * per the LDtk spec the root `levels` array is kept but EMPTY in this shape).
8
+ *
9
+ * This is the single place that decides which shape a document uses - every
10
+ * consumer that needs "all levels, in document order" ({@link import('./loadLdtkMap').loadLdtkMap}'s
11
+ * external `.ldtkl` resolution, {@link import('./ldtkToTileMap').ldtkToTileMap}'s
12
+ * conversion, and {@link import('./LdtkMap').LdtkMap.getLevelByName}'s lookup)
13
+ * goes through this function rather than re-deriving the single/multi-world
14
+ * detection independently.
15
+ */
16
+ const getLdtkLevelEntries = (data) => {
17
+ if (data.worlds && data.worlds.length > 0) {
18
+ const entries = [];
19
+ for (const world of data.worlds) for (const level of world.levels) entries.push({
20
+ level,
21
+ worldIid: world.iid
22
+ });
23
+ return entries;
24
+ }
25
+ return data.levels.map((level) => ({
26
+ level,
27
+ worldIid: void 0
28
+ }));
29
+ };
27
30
 
31
+ //#endregion
28
32
  export { getLdtkLevelEntries };
29
- //# sourceMappingURL=ldtkLevelEntries.js.map
33
+ //# sourceMappingURL=ldtkLevelEntries.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ldtkLevelEntries.js","sources":["../../../src/ldtkLevelEntries.ts"],"sourcesContent":[null],"names":[],"mappings":"AAcA;;;;;;;;;;;;;AAaG;AACG,SAAU,mBAAmB,CAAC,IAAc,EAAA;AAChD,IAAA,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE;QACzC,MAAM,OAAO,GAAqB,EAAE;AACpC,QAAA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE;AAC/B,YAAA,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE;AAChC,gBAAA,OAAO,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC;YAC9C;QACF;AACA,QAAA,OAAO,OAAO;IAChB;IAEA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AACnE;;;;"}
1
+ {"version":3,"file":"ldtkLevelEntries.js","names":[],"sources":["../../src/ldtkLevelEntries.ts"],"sourcesContent":["import type { LdtkData, LdtkLevel } from './LdtkData';\n\n/**\n * One level from a (possibly multi-world) {@link LdtkData} document, paired\n * with the {@link import('./LdtkData').LdtkWorldData.iid} of the world it\n * belongs to. `worldIid` is `undefined` when the document uses the legacy\n * single-world shape (`data.levels`, no `worlds[]`) - the overwhelmingly\n * common case.\n */\nexport interface LdtkLevelEntry {\n readonly level: LdtkLevel;\n readonly worldIid: string | undefined;\n}\n\n/**\n * Flatten a {@link LdtkData} document's levels into one ordered list,\n * abstracting over LDtk's two root shapes: single-world (levels live in the\n * root {@link LdtkData.levels}) and multi-world (levels live in\n * `data.worlds[].levels`, each tagged here with its owning world's `iid`;\n * per the LDtk spec the root `levels` array is kept but EMPTY in this shape).\n *\n * This is the single place that decides which shape a document uses - every\n * consumer that needs \"all levels, in document order\" ({@link import('./loadLdtkMap').loadLdtkMap}'s\n * external `.ldtkl` resolution, {@link import('./ldtkToTileMap').ldtkToTileMap}'s\n * conversion, and {@link import('./LdtkMap').LdtkMap.getLevelByName}'s lookup)\n * goes through this function rather than re-deriving the single/multi-world\n * detection independently.\n */\nexport const getLdtkLevelEntries = (data: LdtkData): readonly LdtkLevelEntry[] => {\n if (data.worlds && data.worlds.length > 0) {\n const entries: LdtkLevelEntry[] = [];\n for (const world of data.worlds) {\n for (const level of world.levels) {\n entries.push({ level, worldIid: world.iid });\n }\n }\n return entries;\n }\n\n return data.levels.map(level => ({ level, worldIid: undefined }));\n};\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,MAAa,uBAAuB,SAA8C;CAChF,IAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;EACzC,MAAM,UAA4B,CAAC;EACnC,KAAK,MAAM,SAAS,KAAK,QACvB,KAAK,MAAM,SAAS,MAAM,QACxB,QAAQ,KAAK;GAAE;GAAO,UAAU,MAAM;EAAI,CAAC;EAG/C,OAAO;CACT;CAEA,OAAO,KAAK,OAAO,KAAI,WAAU;EAAE;EAAO,UAAU;CAAU,EAAE;AAClE"}
@@ -0,0 +1,22 @@
1
+ import type { LdtkData } from './LdtkData';
2
+ /** Resolved runtime parallax transform for one LDtk layer instance. */
3
+ export interface LdtkLayerParallax {
4
+ readonly parallaxX: number;
5
+ readonly parallaxY: number;
6
+ readonly parallaxScale: number;
7
+ /** Definition offset plus LDtk's unscaled-parallax centre compensation. */
8
+ readonly offsetX: number;
9
+ /** Definition offset plus LDtk's unscaled-parallax centre compensation. */
10
+ readonly offsetY: number;
11
+ }
12
+ /**
13
+ * Resolve the runtime parallax transform for a layer instance. Missing
14
+ * definitions and factors use LDtk's defaults: no shift and scale `1`.
15
+ */
16
+ export declare const resolveLdtkLayerParallax: (data: LdtkData, layer: {
17
+ readonly layerDefUid: number;
18
+ readonly __cWid: number;
19
+ readonly __cHei: number;
20
+ readonly __gridSize: number;
21
+ }) => LdtkLayerParallax;
22
+ //# sourceMappingURL=ldtkParallax.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ldtkParallax.d.ts","sourceRoot":"","sources":["../../src/ldtkParallax.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB,GACnC,MAAM,QAAQ,EACd,OAAO;IACL,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B,KACA,iBAaF,CAAC"}
@@ -0,0 +1,22 @@
1
+ //#region src/ldtkParallax.ts
2
+ /**
3
+ * Resolve the runtime parallax transform for a layer instance. Missing
4
+ * definitions and factors use LDtk's defaults: no shift and scale `1`.
5
+ */
6
+ const resolveLdtkLayerParallax = (data, layer) => {
7
+ const layerDef = data.defs.layers.find((def) => def.uid === layer.layerDefUid);
8
+ const factorX = layerDef?.parallaxFactorX ?? 0;
9
+ const factorY = layerDef?.parallaxFactorY ?? 0;
10
+ const scaling = layerDef?.parallaxScaling ?? true;
11
+ return {
12
+ parallaxX: 1 - factorX,
13
+ parallaxY: 1 - factorY,
14
+ parallaxScale: scaling && factorX !== 0 ? Math.max(.01, 1 - factorX) : 1,
15
+ offsetX: (layerDef?.pxOffsetX ?? 0) + (scaling ? 0 : -layer.__cWid * layer.__gridSize * .5 * factorX),
16
+ offsetY: (layerDef?.pxOffsetY ?? 0) + (scaling ? 0 : -layer.__cHei * layer.__gridSize * .5 * factorY)
17
+ };
18
+ };
19
+
20
+ //#endregion
21
+ export { resolveLdtkLayerParallax };
22
+ //# sourceMappingURL=ldtkParallax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ldtkParallax.js","names":[],"sources":["../../src/ldtkParallax.ts"],"sourcesContent":["// LDtk → runtime parallax conversion.\n//\n// LDtk's `parallaxFactorX`/`parallaxFactorY` (declared on `defs.layers[]`,\n// range `[-1, 1]`) use `0` for normal camera speed. The runtime tilemap model\n// uses the opposite convention: `1` is normal speed, and render code derives\n// the camera-relative shift as `camCenter * (1 - parallaxX)`. Therefore the\n// scroll conversion is `runtimeFactor = 1 - ldtkFactor`.\n//\n// LDtk's editor applies one uniform scale derived from the horizontal factor:\n// `max(0.01, 1 - parallaxFactorX)`. Scaling happens around the layer origin.\n// When scaling is disabled, the editor offsets the unscaled layer by half its\n// dimensions times the factor so its centre follows the same parallax path.\n\nimport type { LdtkData } from './LdtkData';\n\n/** Resolved runtime parallax transform for one LDtk layer instance. */\nexport interface LdtkLayerParallax {\n readonly parallaxX: number;\n readonly parallaxY: number;\n readonly parallaxScale: number;\n /** Definition offset plus LDtk's unscaled-parallax centre compensation. */\n readonly offsetX: number;\n /** Definition offset plus LDtk's unscaled-parallax centre compensation. */\n readonly offsetY: number;\n}\n\n/**\n * Resolve the runtime parallax transform for a layer instance. Missing\n * definitions and factors use LDtk's defaults: no shift and scale `1`.\n */\nexport const resolveLdtkLayerParallax = (\n data: LdtkData,\n layer: {\n readonly layerDefUid: number;\n readonly __cWid: number;\n readonly __cHei: number;\n readonly __gridSize: number;\n },\n): LdtkLayerParallax => {\n const layerDef = data.defs.layers.find(def => def.uid === layer.layerDefUid);\n const factorX = layerDef?.parallaxFactorX ?? 0;\n const factorY = layerDef?.parallaxFactorY ?? 0;\n const scaling = layerDef?.parallaxScaling ?? true;\n\n return {\n parallaxX: 1 - factorX,\n parallaxY: 1 - factorY,\n parallaxScale: scaling && factorX !== 0 ? Math.max(0.01, 1 - factorX) : 1,\n offsetX: (layerDef?.pxOffsetX ?? 0) + (scaling ? 0 : -layer.__cWid * layer.__gridSize * 0.5 * factorX),\n offsetY: (layerDef?.pxOffsetY ?? 0) + (scaling ? 0 : -layer.__cHei * layer.__gridSize * 0.5 * factorY),\n };\n};\n"],"mappings":";;;;;AA8BA,MAAa,4BACX,MACA,UAMsB;CACtB,MAAM,WAAW,KAAK,KAAK,OAAO,MAAK,QAAO,IAAI,QAAQ,MAAM,WAAW;CAC3E,MAAM,UAAU,UAAU,mBAAmB;CAC7C,MAAM,UAAU,UAAU,mBAAmB;CAC7C,MAAM,UAAU,UAAU,mBAAmB;CAE7C,OAAO;EACL,WAAW,IAAI;EACf,WAAW,IAAI;EACf,eAAe,WAAW,YAAY,IAAI,KAAK,IAAI,KAAM,IAAI,OAAO,IAAI;EACxE,UAAU,UAAU,aAAa,MAAM,UAAU,IAAI,CAAC,MAAM,SAAS,MAAM,aAAa,KAAM;EAC9F,UAAU,UAAU,aAAa,MAAM,UAAU,IAAI,CAAC,MAAM,SAAS,MAAM,aAAa,KAAM;CAChG;AACF"}
@@ -0,0 +1,20 @@
1
+ import { MapWorld } from '@codexo/exojs-tilemap';
2
+ import type { LdtkData } from './LdtkData';
3
+ /**
4
+ * Build the format-neutral world model for an LDtk document: one
5
+ * {@link MapWorld} per LDtk world, in document order.
6
+ *
7
+ * A single-world project - the overwhelmingly common shape - yields exactly one
8
+ * unnamed world. A multi-world project yields one per entry of `worlds[]`, each
9
+ * named by its identifier, and they stay separate on purpose: LDtk worlds have independent coordinate spaces, so merging them
10
+ * would make {@link MapWorld.bounds} and {@link MapWorld.getLevelsInBounds}
11
+ * report overlaps that do not exist.
12
+ *
13
+ * {@link MapLevel.index} counts across the whole document, matching the
14
+ * flattened order {@link import('./LdtkMap').LdtkMap.levels} uses.
15
+ *
16
+ * Level metadata only: no layer payload is read, so this is safe to call on a
17
+ * document whose external levels have not been fetched.
18
+ */
19
+ export declare const ldtkToMapWorld: (data: LdtkData) => readonly MapWorld[];
20
+ //# sourceMappingURL=ldtkToMapWorld.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ldtkToMapWorld.d.ts","sourceRoot":"","sources":["../../src/ldtkToMapWorld.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAE/D,OAAO,KAAK,EAAE,QAAQ,EAAa,MAAM,YAAY,CAAC;AAyCtD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,GAAI,MAAM,QAAQ,KAAG,SAAS,QAAQ,EAgBhE,CAAC"}