@al8b/map 0.1.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/README.md +24 -0
- package/dist/core/tile-map.d.mts +36 -0
- package/dist/core/tile-map.d.ts +36 -0
- package/dist/core/tile-map.js +361 -0
- package/dist/core/tile-map.js.map +1 -0
- package/dist/core/tile-map.mjs +335 -0
- package/dist/core/tile-map.mjs.map +1 -0
- package/dist/data/loader.d.mts +10 -0
- package/dist/data/loader.d.ts +10 -0
- package/dist/data/loader.js +52 -0
- package/dist/data/loader.js.map +1 -0
- package/dist/data/loader.mjs +28 -0
- package/dist/data/loader.mjs.map +1 -0
- package/dist/data/types.d.mts +29 -0
- package/dist/data/types.d.ts +29 -0
- package/dist/data/types.js +19 -0
- package/dist/data/types.js.map +1 -0
- package/dist/data/types.mjs +1 -0
- package/dist/data/types.mjs.map +1 -0
- package/dist/drawing/renderer.d.mts +14 -0
- package/dist/drawing/renderer.d.ts +14 -0
- package/dist/drawing/renderer.js +108 -0
- package/dist/drawing/renderer.js.map +1 -0
- package/dist/drawing/renderer.mjs +82 -0
- package/dist/drawing/renderer.mjs.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +363 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +335 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shared/references.d.mts +4 -0
- package/dist/shared/references.d.ts +4 -0
- package/dist/shared/references.js +35 -0
- package/dist/shared/references.js.map +1 -0
- package/dist/shared/references.mjs +11 -0
- package/dist/shared/references.mjs.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/drawing/renderer.ts
|
|
22
|
+
var renderer_exports = {};
|
|
23
|
+
__export(renderer_exports, {
|
|
24
|
+
drawTile: () => drawTile,
|
|
25
|
+
ensureCanvas: () => ensureCanvas,
|
|
26
|
+
queueAnimatedTile: () => queueAnimatedTile,
|
|
27
|
+
renderAnimatedTiles: () => renderAnimatedTiles
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(renderer_exports);
|
|
30
|
+
var import_diagnostics = require("@al8b/diagnostics");
|
|
31
|
+
var ensureCanvas = /* @__PURE__ */ __name((state, width, height, blockWidth, blockHeight) => {
|
|
32
|
+
if (!state.canvas) {
|
|
33
|
+
state.canvas = document.createElement("canvas");
|
|
34
|
+
}
|
|
35
|
+
const expectedWidth = width * blockWidth;
|
|
36
|
+
const expectedHeight = height * blockHeight;
|
|
37
|
+
if (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {
|
|
38
|
+
state.canvas.width = expectedWidth;
|
|
39
|
+
state.canvas.height = expectedHeight;
|
|
40
|
+
}
|
|
41
|
+
const ctx = state.canvas.getContext("2d");
|
|
42
|
+
if (!ctx) {
|
|
43
|
+
const diagnostic = (0, import_diagnostics.createDiagnostic)(import_diagnostics.APIErrorCode.E7031);
|
|
44
|
+
const formatted = (0, import_diagnostics.formatForBrowser)(diagnostic);
|
|
45
|
+
throw new Error(formatted);
|
|
46
|
+
}
|
|
47
|
+
ctx.clearRect(0, 0, state.canvas.width, state.canvas.height);
|
|
48
|
+
state.animated = [];
|
|
49
|
+
return ctx;
|
|
50
|
+
}, "ensureCanvas");
|
|
51
|
+
var drawTile = /* @__PURE__ */ __name((ctx, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
52
|
+
const canvas = sprite.frames[0].canvas;
|
|
53
|
+
if (!canvas || canvas.width === 0 || canvas.height === 0) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
if (parsed.subX != null) {
|
|
57
|
+
const tx = parsed.subX * blockWidth;
|
|
58
|
+
const ty = (parsed.subY ?? 0) * blockHeight;
|
|
59
|
+
ctx.drawImage(canvas, tx, ty, blockWidth, blockHeight, blockWidth * gridX, blockHeight * gridY, blockWidth, blockHeight);
|
|
60
|
+
} else {
|
|
61
|
+
ctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);
|
|
62
|
+
}
|
|
63
|
+
return true;
|
|
64
|
+
}, "drawTile");
|
|
65
|
+
var queueAnimatedTile = /* @__PURE__ */ __name((state, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
66
|
+
const tile = {
|
|
67
|
+
x: blockWidth * gridX,
|
|
68
|
+
y: blockHeight * gridY,
|
|
69
|
+
w: blockWidth,
|
|
70
|
+
h: blockHeight,
|
|
71
|
+
sprite
|
|
72
|
+
};
|
|
73
|
+
if (parsed.subX != null) {
|
|
74
|
+
tile.tx = parsed.subX * blockWidth;
|
|
75
|
+
tile.ty = (parsed.subY ?? 0) * blockHeight;
|
|
76
|
+
}
|
|
77
|
+
state.animated.push(tile);
|
|
78
|
+
}, "queueAnimatedTile");
|
|
79
|
+
var renderAnimatedTiles = /* @__PURE__ */ __name((state, blockWidth, blockHeight) => {
|
|
80
|
+
const time = performance.now();
|
|
81
|
+
if (!state.buffer || state.buffer.width !== blockWidth * (state.canvas.width / blockWidth) || state.buffer.height !== blockHeight * (state.canvas.height / blockHeight)) {
|
|
82
|
+
state.buffer = document.createElement("canvas");
|
|
83
|
+
state.buffer.width = state.canvas.width;
|
|
84
|
+
state.buffer.height = state.canvas.height;
|
|
85
|
+
}
|
|
86
|
+
const bufferCtx = state.buffer.getContext("2d");
|
|
87
|
+
bufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);
|
|
88
|
+
bufferCtx.drawImage(state.canvas, 0, 0);
|
|
89
|
+
for (const tile of state.animated) {
|
|
90
|
+
const len = tile.sprite.frames.length;
|
|
91
|
+
const frame = tile.sprite.frames[Math.floor(time / 1e3 * tile.sprite.fps) % len]?.canvas;
|
|
92
|
+
if (!frame) continue;
|
|
93
|
+
if (tile.tx != null && tile.ty != null) {
|
|
94
|
+
bufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);
|
|
95
|
+
} else {
|
|
96
|
+
bufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return state.buffer;
|
|
100
|
+
}, "renderAnimatedTiles");
|
|
101
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
102
|
+
0 && (module.exports = {
|
|
103
|
+
drawTile,
|
|
104
|
+
ensureCanvas,
|
|
105
|
+
queueAnimatedTile,
|
|
106
|
+
renderAnimatedTiles
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/drawing/renderer.ts"],"sourcesContent":["import { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { AnimatedTile, ParsedTile } from \"../data/types\";\n\nexport interface RenderState {\n\tcanvas: HTMLCanvasElement | null;\n\tbuffer: HTMLCanvasElement | null;\n\tanimated: AnimatedTile[];\n}\n\nexport const ensureCanvas = (\n\tstate: RenderState,\n\twidth: number,\n\theight: number,\n\tblockWidth: number,\n\tblockHeight: number,\n): CanvasRenderingContext2D => {\n\tif (!state.canvas) {\n\t\tstate.canvas = document.createElement(\"canvas\");\n\t}\n\tconst expectedWidth = width * blockWidth;\n\tconst expectedHeight = height * blockHeight;\n\tif (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {\n\t\tstate.canvas.width = expectedWidth;\n\t\tstate.canvas.height = expectedHeight;\n\t}\n\tconst ctx = state.canvas.getContext(\"2d\");\n\tif (!ctx) {\n\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7031);\n\t\tconst formatted = formatForBrowser(diagnostic);\n\t\tthrow new Error(formatted);\n\t}\n\tctx.clearRect(0, 0, state.canvas.width, state.canvas.height);\n\tstate.animated = [];\n\treturn ctx;\n};\n\nexport const drawTile = (\n\tctx: CanvasRenderingContext2D,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): boolean => {\n\tconst canvas = sprite.frames[0].canvas;\n\tif (!canvas || canvas.width === 0 || canvas.height === 0) {\n\t\treturn false;\n\t}\n\tif (parsed.subX != null) {\n\t\tconst tx = parsed.subX * blockWidth;\n\t\tconst ty = (parsed.subY ?? 0) * blockHeight;\n\t\tctx.drawImage(\n\t\t\tcanvas,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t\tblockWidth * gridX,\n\t\t\tblockHeight * gridY,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t);\n\t} else {\n\t\tctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);\n\t}\n\treturn true;\n};\n\nexport const queueAnimatedTile = (\n\tstate: RenderState,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): void => {\n\tconst tile: AnimatedTile = {\n\t\tx: blockWidth * gridX,\n\t\ty: blockHeight * gridY,\n\t\tw: blockWidth,\n\t\th: blockHeight,\n\t\tsprite,\n\t};\n\tif (parsed.subX != null) {\n\t\ttile.tx = parsed.subX * blockWidth;\n\t\ttile.ty = (parsed.subY ?? 0) * blockHeight;\n\t}\n\tstate.animated.push(tile);\n};\n\nexport const renderAnimatedTiles = (state: RenderState, blockWidth: number, blockHeight: number): HTMLCanvasElement => {\n\tconst time = performance.now();\n\tif (\n\t\t!state.buffer ||\n\t\tstate.buffer.width !== blockWidth * (state.canvas!.width / blockWidth) ||\n\t\tstate.buffer.height !== blockHeight * (state.canvas!.height / blockHeight)\n\t) {\n\t\tstate.buffer = document.createElement(\"canvas\");\n\t\tstate.buffer.width = state.canvas!.width;\n\t\tstate.buffer.height = state.canvas!.height;\n\t}\n\tconst bufferCtx = state.buffer.getContext(\"2d\")!;\n\tbufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);\n\tbufferCtx.drawImage(state.canvas!, 0, 0);\n\tfor (const tile of state.animated) {\n\t\tconst len = tile.sprite.frames.length;\n\t\tconst frame = tile.sprite.frames[Math.floor((time / 1000) * tile.sprite.fps) % len]?.canvas;\n\t\tif (!frame) continue;\n\t\tif (tile.tx != null && tile.ty != null) {\n\t\t\tbufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);\n\t\t} else {\n\t\t\tbufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);\n\t\t}\n\t}\n\treturn state.buffer;\n};\n"],"mappings":"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","names":["ensureCanvas","state","width","height","blockWidth","blockHeight","canvas","document","createElement","expectedWidth","expectedHeight","ctx","getContext","diagnostic","createDiagnostic","APIErrorCode","E7031","formatted","formatForBrowser","Error","clearRect","animated","drawTile","sprite","gridX","gridY","parsed","frames","subX","tx","ty","subY","drawImage","queueAnimatedTile","tile","x","y","w","h","push","renderAnimatedTiles","time","performance","now","buffer","bufferCtx","len","length","frame","Math","floor","fps"]}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/drawing/renderer.ts
|
|
5
|
+
import { APIErrorCode, createDiagnostic, formatForBrowser } from "@al8b/diagnostics";
|
|
6
|
+
var ensureCanvas = /* @__PURE__ */ __name((state, width, height, blockWidth, blockHeight) => {
|
|
7
|
+
if (!state.canvas) {
|
|
8
|
+
state.canvas = document.createElement("canvas");
|
|
9
|
+
}
|
|
10
|
+
const expectedWidth = width * blockWidth;
|
|
11
|
+
const expectedHeight = height * blockHeight;
|
|
12
|
+
if (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {
|
|
13
|
+
state.canvas.width = expectedWidth;
|
|
14
|
+
state.canvas.height = expectedHeight;
|
|
15
|
+
}
|
|
16
|
+
const ctx = state.canvas.getContext("2d");
|
|
17
|
+
if (!ctx) {
|
|
18
|
+
const diagnostic = createDiagnostic(APIErrorCode.E7031);
|
|
19
|
+
const formatted = formatForBrowser(diagnostic);
|
|
20
|
+
throw new Error(formatted);
|
|
21
|
+
}
|
|
22
|
+
ctx.clearRect(0, 0, state.canvas.width, state.canvas.height);
|
|
23
|
+
state.animated = [];
|
|
24
|
+
return ctx;
|
|
25
|
+
}, "ensureCanvas");
|
|
26
|
+
var drawTile = /* @__PURE__ */ __name((ctx, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
27
|
+
const canvas = sprite.frames[0].canvas;
|
|
28
|
+
if (!canvas || canvas.width === 0 || canvas.height === 0) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
if (parsed.subX != null) {
|
|
32
|
+
const tx = parsed.subX * blockWidth;
|
|
33
|
+
const ty = (parsed.subY ?? 0) * blockHeight;
|
|
34
|
+
ctx.drawImage(canvas, tx, ty, blockWidth, blockHeight, blockWidth * gridX, blockHeight * gridY, blockWidth, blockHeight);
|
|
35
|
+
} else {
|
|
36
|
+
ctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}, "drawTile");
|
|
40
|
+
var queueAnimatedTile = /* @__PURE__ */ __name((state, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
41
|
+
const tile = {
|
|
42
|
+
x: blockWidth * gridX,
|
|
43
|
+
y: blockHeight * gridY,
|
|
44
|
+
w: blockWidth,
|
|
45
|
+
h: blockHeight,
|
|
46
|
+
sprite
|
|
47
|
+
};
|
|
48
|
+
if (parsed.subX != null) {
|
|
49
|
+
tile.tx = parsed.subX * blockWidth;
|
|
50
|
+
tile.ty = (parsed.subY ?? 0) * blockHeight;
|
|
51
|
+
}
|
|
52
|
+
state.animated.push(tile);
|
|
53
|
+
}, "queueAnimatedTile");
|
|
54
|
+
var renderAnimatedTiles = /* @__PURE__ */ __name((state, blockWidth, blockHeight) => {
|
|
55
|
+
const time = performance.now();
|
|
56
|
+
if (!state.buffer || state.buffer.width !== blockWidth * (state.canvas.width / blockWidth) || state.buffer.height !== blockHeight * (state.canvas.height / blockHeight)) {
|
|
57
|
+
state.buffer = document.createElement("canvas");
|
|
58
|
+
state.buffer.width = state.canvas.width;
|
|
59
|
+
state.buffer.height = state.canvas.height;
|
|
60
|
+
}
|
|
61
|
+
const bufferCtx = state.buffer.getContext("2d");
|
|
62
|
+
bufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);
|
|
63
|
+
bufferCtx.drawImage(state.canvas, 0, 0);
|
|
64
|
+
for (const tile of state.animated) {
|
|
65
|
+
const len = tile.sprite.frames.length;
|
|
66
|
+
const frame = tile.sprite.frames[Math.floor(time / 1e3 * tile.sprite.fps) % len]?.canvas;
|
|
67
|
+
if (!frame) continue;
|
|
68
|
+
if (tile.tx != null && tile.ty != null) {
|
|
69
|
+
bufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);
|
|
70
|
+
} else {
|
|
71
|
+
bufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return state.buffer;
|
|
75
|
+
}, "renderAnimatedTiles");
|
|
76
|
+
export {
|
|
77
|
+
drawTile,
|
|
78
|
+
ensureCanvas,
|
|
79
|
+
queueAnimatedTile,
|
|
80
|
+
renderAnimatedTiles
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=renderer.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/drawing/renderer.ts"],"sourcesContent":["import { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { AnimatedTile, ParsedTile } from \"../data/types\";\n\nexport interface RenderState {\n\tcanvas: HTMLCanvasElement | null;\n\tbuffer: HTMLCanvasElement | null;\n\tanimated: AnimatedTile[];\n}\n\nexport const ensureCanvas = (\n\tstate: RenderState,\n\twidth: number,\n\theight: number,\n\tblockWidth: number,\n\tblockHeight: number,\n): CanvasRenderingContext2D => {\n\tif (!state.canvas) {\n\t\tstate.canvas = document.createElement(\"canvas\");\n\t}\n\tconst expectedWidth = width * blockWidth;\n\tconst expectedHeight = height * blockHeight;\n\tif (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {\n\t\tstate.canvas.width = expectedWidth;\n\t\tstate.canvas.height = expectedHeight;\n\t}\n\tconst ctx = state.canvas.getContext(\"2d\");\n\tif (!ctx) {\n\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7031);\n\t\tconst formatted = formatForBrowser(diagnostic);\n\t\tthrow new Error(formatted);\n\t}\n\tctx.clearRect(0, 0, state.canvas.width, state.canvas.height);\n\tstate.animated = [];\n\treturn ctx;\n};\n\nexport const drawTile = (\n\tctx: CanvasRenderingContext2D,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): boolean => {\n\tconst canvas = sprite.frames[0].canvas;\n\tif (!canvas || canvas.width === 0 || canvas.height === 0) {\n\t\treturn false;\n\t}\n\tif (parsed.subX != null) {\n\t\tconst tx = parsed.subX * blockWidth;\n\t\tconst ty = (parsed.subY ?? 0) * blockHeight;\n\t\tctx.drawImage(\n\t\t\tcanvas,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t\tblockWidth * gridX,\n\t\t\tblockHeight * gridY,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t);\n\t} else {\n\t\tctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);\n\t}\n\treturn true;\n};\n\nexport const queueAnimatedTile = (\n\tstate: RenderState,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): void => {\n\tconst tile: AnimatedTile = {\n\t\tx: blockWidth * gridX,\n\t\ty: blockHeight * gridY,\n\t\tw: blockWidth,\n\t\th: blockHeight,\n\t\tsprite,\n\t};\n\tif (parsed.subX != null) {\n\t\ttile.tx = parsed.subX * blockWidth;\n\t\ttile.ty = (parsed.subY ?? 0) * blockHeight;\n\t}\n\tstate.animated.push(tile);\n};\n\nexport const renderAnimatedTiles = (state: RenderState, blockWidth: number, blockHeight: number): HTMLCanvasElement => {\n\tconst time = performance.now();\n\tif (\n\t\t!state.buffer ||\n\t\tstate.buffer.width !== blockWidth * (state.canvas!.width / blockWidth) ||\n\t\tstate.buffer.height !== blockHeight * (state.canvas!.height / blockHeight)\n\t) {\n\t\tstate.buffer = document.createElement(\"canvas\");\n\t\tstate.buffer.width = state.canvas!.width;\n\t\tstate.buffer.height = state.canvas!.height;\n\t}\n\tconst bufferCtx = state.buffer.getContext(\"2d\")!;\n\tbufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);\n\tbufferCtx.drawImage(state.canvas!, 0, 0);\n\tfor (const tile of state.animated) {\n\t\tconst len = tile.sprite.frames.length;\n\t\tconst frame = tile.sprite.frames[Math.floor((time / 1000) * tile.sprite.fps) % len]?.canvas;\n\t\tif (!frame) continue;\n\t\tif (tile.tx != null && tile.ty != null) {\n\t\t\tbufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);\n\t\t} else {\n\t\t\tbufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);\n\t\t}\n\t}\n\treturn state.buffer;\n};\n"],"mappings":"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","names":["APIErrorCode","createDiagnostic","formatForBrowser","ensureCanvas","state","width","height","blockWidth","blockHeight","canvas","document","createElement","expectedWidth","expectedHeight","ctx","getContext","diagnostic","createDiagnostic","APIErrorCode","E7031","formatted","formatForBrowser","Error","clearRect","animated","drawTile","sprite","gridX","gridY","parsed","frames","subX","tx","ty","subY","drawImage","queueAnimatedTile","tile","x","y","w","h","push","renderAnimatedTiles","time","performance","now","buffer","bufferCtx","len","length","frame","Math","floor","fps"]}
|
package/dist/index.d.mts
ADDED
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
var index_exports = {};
|
|
23
|
+
__export(index_exports, {
|
|
24
|
+
LoadMap: () => LoadMap,
|
|
25
|
+
SaveMap: () => SaveMap,
|
|
26
|
+
TileMap: () => TileMap,
|
|
27
|
+
UpdateMap: () => UpdateMap
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(index_exports);
|
|
30
|
+
|
|
31
|
+
// src/core/tile-map.ts
|
|
32
|
+
var import_diagnostics2 = require("@al8b/diagnostics");
|
|
33
|
+
|
|
34
|
+
// src/drawing/renderer.ts
|
|
35
|
+
var import_diagnostics = require("@al8b/diagnostics");
|
|
36
|
+
var ensureCanvas = /* @__PURE__ */ __name((state, width, height, blockWidth, blockHeight) => {
|
|
37
|
+
if (!state.canvas) {
|
|
38
|
+
state.canvas = document.createElement("canvas");
|
|
39
|
+
}
|
|
40
|
+
const expectedWidth = width * blockWidth;
|
|
41
|
+
const expectedHeight = height * blockHeight;
|
|
42
|
+
if (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {
|
|
43
|
+
state.canvas.width = expectedWidth;
|
|
44
|
+
state.canvas.height = expectedHeight;
|
|
45
|
+
}
|
|
46
|
+
const ctx = state.canvas.getContext("2d");
|
|
47
|
+
if (!ctx) {
|
|
48
|
+
const diagnostic = (0, import_diagnostics.createDiagnostic)(import_diagnostics.APIErrorCode.E7031);
|
|
49
|
+
const formatted = (0, import_diagnostics.formatForBrowser)(diagnostic);
|
|
50
|
+
throw new Error(formatted);
|
|
51
|
+
}
|
|
52
|
+
ctx.clearRect(0, 0, state.canvas.width, state.canvas.height);
|
|
53
|
+
state.animated = [];
|
|
54
|
+
return ctx;
|
|
55
|
+
}, "ensureCanvas");
|
|
56
|
+
var drawTile = /* @__PURE__ */ __name((ctx, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
57
|
+
const canvas = sprite.frames[0].canvas;
|
|
58
|
+
if (!canvas || canvas.width === 0 || canvas.height === 0) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
if (parsed.subX != null) {
|
|
62
|
+
const tx = parsed.subX * blockWidth;
|
|
63
|
+
const ty = (parsed.subY ?? 0) * blockHeight;
|
|
64
|
+
ctx.drawImage(canvas, tx, ty, blockWidth, blockHeight, blockWidth * gridX, blockHeight * gridY, blockWidth, blockHeight);
|
|
65
|
+
} else {
|
|
66
|
+
ctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}, "drawTile");
|
|
70
|
+
var queueAnimatedTile = /* @__PURE__ */ __name((state, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
71
|
+
const tile = {
|
|
72
|
+
x: blockWidth * gridX,
|
|
73
|
+
y: blockHeight * gridY,
|
|
74
|
+
w: blockWidth,
|
|
75
|
+
h: blockHeight,
|
|
76
|
+
sprite
|
|
77
|
+
};
|
|
78
|
+
if (parsed.subX != null) {
|
|
79
|
+
tile.tx = parsed.subX * blockWidth;
|
|
80
|
+
tile.ty = (parsed.subY ?? 0) * blockHeight;
|
|
81
|
+
}
|
|
82
|
+
state.animated.push(tile);
|
|
83
|
+
}, "queueAnimatedTile");
|
|
84
|
+
var renderAnimatedTiles = /* @__PURE__ */ __name((state, blockWidth, blockHeight) => {
|
|
85
|
+
const time = performance.now();
|
|
86
|
+
if (!state.buffer || state.buffer.width !== blockWidth * (state.canvas.width / blockWidth) || state.buffer.height !== blockHeight * (state.canvas.height / blockHeight)) {
|
|
87
|
+
state.buffer = document.createElement("canvas");
|
|
88
|
+
state.buffer.width = state.canvas.width;
|
|
89
|
+
state.buffer.height = state.canvas.height;
|
|
90
|
+
}
|
|
91
|
+
const bufferCtx = state.buffer.getContext("2d");
|
|
92
|
+
bufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);
|
|
93
|
+
bufferCtx.drawImage(state.canvas, 0, 0);
|
|
94
|
+
for (const tile of state.animated) {
|
|
95
|
+
const len = tile.sprite.frames.length;
|
|
96
|
+
const frame = tile.sprite.frames[Math.floor(time / 1e3 * tile.sprite.fps) % len]?.canvas;
|
|
97
|
+
if (!frame) continue;
|
|
98
|
+
if (tile.tx != null && tile.ty != null) {
|
|
99
|
+
bufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);
|
|
100
|
+
} else {
|
|
101
|
+
bufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return state.buffer;
|
|
105
|
+
}, "renderAnimatedTiles");
|
|
106
|
+
|
|
107
|
+
// src/shared/references.ts
|
|
108
|
+
var normalizeRefForStorage = /* @__PURE__ */ __name((ref) => ref.replace(/\//g, "-"), "normalizeRefForStorage");
|
|
109
|
+
var normalizeRefForUsage = /* @__PURE__ */ __name((ref) => ref.replace(/-/g, "/"), "normalizeRefForUsage");
|
|
110
|
+
|
|
111
|
+
// src/core/tile-map.ts
|
|
112
|
+
function parseTileRef(entry) {
|
|
113
|
+
const colonIdx = entry.indexOf(":");
|
|
114
|
+
if (colonIdx === -1) {
|
|
115
|
+
return {
|
|
116
|
+
spriteName: entry
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const spriteName = entry.substring(0, colonIdx);
|
|
120
|
+
const coords = entry.substring(colonIdx + 1);
|
|
121
|
+
const commaIdx = coords.indexOf(",");
|
|
122
|
+
if (commaIdx === -1) {
|
|
123
|
+
return {
|
|
124
|
+
spriteName,
|
|
125
|
+
subX: Number.parseInt(coords, 10)
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
spriteName,
|
|
130
|
+
subX: Number.parseInt(coords.substring(0, commaIdx), 10),
|
|
131
|
+
subY: Number.parseInt(coords.substring(commaIdx + 1), 10)
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
__name(parseTileRef, "parseTileRef");
|
|
135
|
+
var TileMap = class _TileMap {
|
|
136
|
+
static {
|
|
137
|
+
__name(this, "TileMap");
|
|
138
|
+
}
|
|
139
|
+
width;
|
|
140
|
+
height;
|
|
141
|
+
block_width;
|
|
142
|
+
block_height;
|
|
143
|
+
sprites;
|
|
144
|
+
map = [];
|
|
145
|
+
ready = true;
|
|
146
|
+
needs_update = false;
|
|
147
|
+
name = "";
|
|
148
|
+
parsedMap = [];
|
|
149
|
+
renderState = {
|
|
150
|
+
canvas: null,
|
|
151
|
+
buffer: null,
|
|
152
|
+
animated: []
|
|
153
|
+
};
|
|
154
|
+
constructor(width, height, block_width, block_height, sprites) {
|
|
155
|
+
if (width <= 0 || height <= 0 || !isFinite(width) || !isFinite(height)) {
|
|
156
|
+
const diagnostic = (0, import_diagnostics2.createDiagnostic)(import_diagnostics2.APIErrorCode.E7034, {
|
|
157
|
+
data: {
|
|
158
|
+
width,
|
|
159
|
+
height
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
const formatted = (0, import_diagnostics2.formatForBrowser)(diagnostic);
|
|
163
|
+
throw new Error(formatted);
|
|
164
|
+
}
|
|
165
|
+
this.width = width;
|
|
166
|
+
this.height = height;
|
|
167
|
+
this.block_width = block_width;
|
|
168
|
+
this.block_height = block_height;
|
|
169
|
+
this.sprites = sprites ?? {};
|
|
170
|
+
this.clear();
|
|
171
|
+
}
|
|
172
|
+
clear() {
|
|
173
|
+
for (let j = 0; j < this.height; j++) {
|
|
174
|
+
for (let i = 0; i < this.width; i++) {
|
|
175
|
+
const idx = i + j * this.width;
|
|
176
|
+
this.map[idx] = null;
|
|
177
|
+
this.parsedMap[idx] = null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
set(x, y, ref) {
|
|
182
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
let normalized = ref;
|
|
186
|
+
if (typeof normalized === "string") {
|
|
187
|
+
normalized = normalizeRefForStorage(normalized);
|
|
188
|
+
}
|
|
189
|
+
const idx = x + y * this.width;
|
|
190
|
+
this.map[idx] = normalized;
|
|
191
|
+
this.parsedMap[idx] = normalized ? parseTileRef(normalized) : null;
|
|
192
|
+
this.needs_update = true;
|
|
193
|
+
}
|
|
194
|
+
get(x, y) {
|
|
195
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {
|
|
196
|
+
return 0;
|
|
197
|
+
}
|
|
198
|
+
let cell = this.map[x + y * this.width];
|
|
199
|
+
if (typeof cell === "string") {
|
|
200
|
+
cell = normalizeRefForUsage(cell);
|
|
201
|
+
}
|
|
202
|
+
return cell || 0;
|
|
203
|
+
}
|
|
204
|
+
getCanvas() {
|
|
205
|
+
if (this.renderState.canvas == null || this.needs_update) {
|
|
206
|
+
this.update();
|
|
207
|
+
}
|
|
208
|
+
return this.renderState.canvas;
|
|
209
|
+
}
|
|
210
|
+
draw(context, x, y, w, h) {
|
|
211
|
+
if (this.renderState.animated.length > 0) {
|
|
212
|
+
const buffer = renderAnimatedTiles(this.renderState, this.block_width, this.block_height);
|
|
213
|
+
context.drawImage(buffer, x, y, w, h);
|
|
214
|
+
} else {
|
|
215
|
+
context.drawImage(this.getCanvas(), x, y, w, h);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
update() {
|
|
219
|
+
this.needs_update = false;
|
|
220
|
+
const context = ensureCanvas(this.renderState, this.width, this.height, this.block_width, this.block_height);
|
|
221
|
+
for (let j = 0; j < this.height; j++) {
|
|
222
|
+
for (let i = 0; i < this.width; i++) {
|
|
223
|
+
const index = i + (this.height - 1 - j) * this.width;
|
|
224
|
+
const parsed = this.parsedMap[index];
|
|
225
|
+
if (!parsed) continue;
|
|
226
|
+
const sprite = this.sprites[parsed.spriteName] || this.sprites[normalizeRefForUsage(parsed.spriteName)];
|
|
227
|
+
if (!sprite || !sprite.frames[0]) continue;
|
|
228
|
+
if (sprite.frames.length > 1) {
|
|
229
|
+
queueAnimatedTile(this.renderState, sprite, this.block_width, this.block_height, i, j, parsed);
|
|
230
|
+
} else {
|
|
231
|
+
drawTile(context, sprite, this.block_width, this.block_height, i, j, parsed);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
loadFile(url, loaded) {
|
|
237
|
+
const req = new XMLHttpRequest();
|
|
238
|
+
req.onreadystatechange = () => {
|
|
239
|
+
if (req.readyState === XMLHttpRequest.DONE && req.status === 200) {
|
|
240
|
+
this.load(req.responseText, this.sprites);
|
|
241
|
+
this.update();
|
|
242
|
+
loaded?.();
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
req.open("GET", url);
|
|
246
|
+
req.send();
|
|
247
|
+
}
|
|
248
|
+
load(data, sprites) {
|
|
249
|
+
const parsed = JSON.parse(data);
|
|
250
|
+
this.width = parsed.width;
|
|
251
|
+
this.height = parsed.height;
|
|
252
|
+
this.block_width = parsed.block_width;
|
|
253
|
+
this.block_height = parsed.block_height;
|
|
254
|
+
this.sprites = sprites ?? this.sprites;
|
|
255
|
+
for (let j = 0; j < parsed.height; j++) {
|
|
256
|
+
for (let i = 0; i < parsed.width; i++) {
|
|
257
|
+
const idx = i + j * parsed.width;
|
|
258
|
+
const value = parsed.data[idx];
|
|
259
|
+
if (value > 0) {
|
|
260
|
+
const ref = parsed.sprites[value];
|
|
261
|
+
this.map[idx] = ref;
|
|
262
|
+
this.parsedMap[idx] = parseTileRef(ref);
|
|
263
|
+
} else {
|
|
264
|
+
this.map[idx] = null;
|
|
265
|
+
this.parsedMap[idx] = null;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
this.needs_update = true;
|
|
270
|
+
}
|
|
271
|
+
clone() {
|
|
272
|
+
const duplicate = new _TileMap(this.width, this.height, this.block_width, this.block_height, this.sprites);
|
|
273
|
+
for (let j = 0; j < this.height; j++) {
|
|
274
|
+
for (let i = 0; i < this.width; i++) {
|
|
275
|
+
const idx = i + j * this.width;
|
|
276
|
+
duplicate.map[idx] = this.map[idx];
|
|
277
|
+
duplicate.parsedMap[idx] = this.parsedMap[idx];
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
duplicate.needs_update = true;
|
|
281
|
+
return duplicate;
|
|
282
|
+
}
|
|
283
|
+
copyFrom(map) {
|
|
284
|
+
this.width = map.width;
|
|
285
|
+
this.height = map.height;
|
|
286
|
+
this.block_width = map.block_width;
|
|
287
|
+
this.block_height = map.block_height;
|
|
288
|
+
for (let j = 0; j < this.height; j++) {
|
|
289
|
+
for (let i = 0; i < this.width; i++) {
|
|
290
|
+
const idx = i + j * this.width;
|
|
291
|
+
this.map[idx] = map.map[idx];
|
|
292
|
+
this.parsedMap[idx] = map.parsedMap[idx];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
this.update();
|
|
296
|
+
return this;
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
function LoadMap(url, sprites, loaded) {
|
|
300
|
+
const map = new TileMap(1, 1, 1, 1, sprites);
|
|
301
|
+
map.ready = false;
|
|
302
|
+
const req = new XMLHttpRequest();
|
|
303
|
+
req.onreadystatechange = () => {
|
|
304
|
+
if (req.readyState === XMLHttpRequest.DONE) {
|
|
305
|
+
map.ready = true;
|
|
306
|
+
if (req.status === 200) {
|
|
307
|
+
UpdateMap(map, req.responseText, sprites);
|
|
308
|
+
}
|
|
309
|
+
map.needs_update = true;
|
|
310
|
+
loaded?.();
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
req.open("GET", url);
|
|
314
|
+
req.send();
|
|
315
|
+
return map;
|
|
316
|
+
}
|
|
317
|
+
__name(LoadMap, "LoadMap");
|
|
318
|
+
function UpdateMap(map, data, sprites) {
|
|
319
|
+
map.load(data, sprites ?? map.sprites);
|
|
320
|
+
return map;
|
|
321
|
+
}
|
|
322
|
+
__name(UpdateMap, "UpdateMap");
|
|
323
|
+
function SaveMap(map) {
|
|
324
|
+
let index = 1;
|
|
325
|
+
const list = [
|
|
326
|
+
0
|
|
327
|
+
];
|
|
328
|
+
const table = {};
|
|
329
|
+
for (let j = 0; j < map.height; j++) {
|
|
330
|
+
for (let i = 0; i < map.width; i++) {
|
|
331
|
+
const entry = map.map[i + j * map.width];
|
|
332
|
+
if (entry && entry.length > 0 && table[entry] == null) {
|
|
333
|
+
list.push(entry);
|
|
334
|
+
table[entry] = index++;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const serialized = [];
|
|
339
|
+
for (let j = 0; j < map.height; j++) {
|
|
340
|
+
for (let i = 0; i < map.width; i++) {
|
|
341
|
+
const entry = map.map[i + j * map.width];
|
|
342
|
+
serialized[i + j * map.width] = entry && entry.length > 0 ? table[entry] : 0;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const payload = {
|
|
346
|
+
width: map.width,
|
|
347
|
+
height: map.height,
|
|
348
|
+
block_width: map.block_width,
|
|
349
|
+
block_height: map.block_height,
|
|
350
|
+
sprites: list,
|
|
351
|
+
data: serialized
|
|
352
|
+
};
|
|
353
|
+
return JSON.stringify(payload);
|
|
354
|
+
}
|
|
355
|
+
__name(SaveMap, "SaveMap");
|
|
356
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
357
|
+
0 && (module.exports = {
|
|
358
|
+
LoadMap,
|
|
359
|
+
SaveMap,
|
|
360
|
+
TileMap,
|
|
361
|
+
UpdateMap
|
|
362
|
+
});
|
|
363
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/core/tile-map.ts","../src/drawing/renderer.ts","../src/shared/references.ts"],"sourcesContent":["/**\n * @al8b/map - Tile map management system\n *\n * Architecture:\n * - core/: TileMap runtime with load/update/save helpers\n * - drawing/: Canvas rendering utilities for animated tiles\n * - shared/: Reference normalization utilities\n * - data/: Raw map data types and loaders\n */\n\nexport { LoadMap, SaveMap, TileMap, UpdateMap } from \"./core/tile-map\";\nexport type { MapData } from \"./data/types\";\n","/**\n * TileMap - Tile-based map implementation with sprite rendering support.\n */\n\nimport { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { MapData, ParsedTile, SpriteDictionary } from \"../data/types\";\nimport { drawTile, ensureCanvas, queueAnimatedTile, type RenderState, renderAnimatedTiles } from \"../drawing/renderer\";\nimport { normalizeRefForStorage, normalizeRefForUsage } from \"../shared/references\";\n\n/**\n * Parse a tile reference string into a cached ParsedTile object.\n * Input format: \"spriteName\" or \"spriteName:subX,subY\"\n */\nfunction parseTileRef(entry: string): ParsedTile {\n\tconst colonIdx = entry.indexOf(\":\");\n\tif (colonIdx === -1) {\n\t\treturn { spriteName: entry };\n\t}\n\tconst spriteName = entry.substring(0, colonIdx);\n\tconst coords = entry.substring(colonIdx + 1);\n\tconst commaIdx = coords.indexOf(\",\");\n\tif (commaIdx === -1) {\n\t\treturn { spriteName, subX: Number.parseInt(coords, 10) };\n\t}\n\treturn {\n\t\tspriteName,\n\t\tsubX: Number.parseInt(coords.substring(0, commaIdx), 10),\n\t\tsubY: Number.parseInt(coords.substring(commaIdx + 1), 10),\n\t};\n}\n\nexport class TileMap {\n\tpublic width: number;\n\tpublic height: number;\n\tpublic block_width: number;\n\tpublic block_height: number;\n\tpublic sprites: SpriteDictionary;\n\tpublic map: (string | null)[] = [];\n\tpublic ready = true;\n\tpublic needs_update = false;\n\tpublic name = \"\";\n\tprivate parsedMap: (ParsedTile | null)[] = [];\n\tprivate readonly renderState: RenderState = {\n\t\tcanvas: null,\n\t\tbuffer: null,\n\t\tanimated: [],\n\t};\n\n\tconstructor(\n\t\twidth: number,\n\t\theight: number,\n\t\tblock_width: number,\n\t\tblock_height: number,\n\t\tsprites?: Record<string, Sprite>,\n\t) {\n\t\t// Validate map dimensions to ensure positive, finite values\n\t\tif (width <= 0 || height <= 0 || !isFinite(width) || !isFinite(height)) {\n\t\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7034, {\n\t\t\t\tdata: {\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst formatted = formatForBrowser(diagnostic);\n\t\t\tthrow new Error(formatted);\n\t\t}\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t\tthis.block_width = block_width;\n\t\tthis.block_height = block_height;\n\t\tthis.sprites = sprites ?? {};\n\t\tthis.clear();\n\t}\n\n\tclear(): void {\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tthis.map[idx] = null;\n\t\t\t\tthis.parsedMap[idx] = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tset(x: number, y: number, ref: string | null): void {\n\t\t// Validate tile coordinates are within map bounds\n\t\tif (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {\n\t\t\t// Silent fail: TileMap lacks runtime reference for error reporting\n\t\t\t// Out-of-bounds access is ignored to prevent crashes during development\n\t\t\treturn;\n\t\t}\n\n\t\tlet normalized = ref;\n\t\tif (typeof normalized === \"string\") {\n\t\t\tnormalized = normalizeRefForStorage(normalized);\n\t\t}\n\t\tconst idx = x + y * this.width;\n\t\tthis.map[idx] = normalized;\n\t\tthis.parsedMap[idx] = normalized ? parseTileRef(normalized) : null;\n\t\tthis.needs_update = true;\n\t}\n\n\tget(x: number, y: number): string | number | null {\n\t\t// Validate tile coordinates are within map bounds\n\t\tif (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {\n\t\t\t// Silent fail: TileMap lacks runtime reference for error reporting\n\t\t\t// Returns 0 for out-of-bounds access to maintain backward compatibility\n\t\t\treturn 0;\n\t\t}\n\t\tlet cell = this.map[x + y * this.width];\n\t\tif (typeof cell === \"string\") {\n\t\t\tcell = normalizeRefForUsage(cell);\n\t\t}\n\t\treturn cell || 0;\n\t}\n\n\tgetCanvas(): HTMLCanvasElement {\n\t\tif (this.renderState.canvas == null || this.needs_update) {\n\t\t\tthis.update();\n\t\t}\n\t\treturn this.renderState.canvas!;\n\t}\n\n\tdraw(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number): void {\n\t\tif (this.renderState.animated.length > 0) {\n\t\t\tconst buffer = renderAnimatedTiles(this.renderState, this.block_width, this.block_height);\n\t\t\tcontext.drawImage(buffer, x, y, w, h);\n\t\t} else {\n\t\t\tcontext.drawImage(this.getCanvas(), x, y, w, h);\n\t\t}\n\t}\n\n\tupdate(): void {\n\t\tthis.needs_update = false;\n\t\tconst context = ensureCanvas(this.renderState, this.width, this.height, this.block_width, this.block_height);\n\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst index = i + (this.height - 1 - j) * this.width;\n\t\t\t\tconst parsed = this.parsedMap[index];\n\t\t\t\tif (!parsed) continue;\n\n\t\t\t\tconst sprite =\n\t\t\t\t\tthis.sprites[parsed.spriteName] || this.sprites[normalizeRefForUsage(parsed.spriteName)];\n\t\t\t\tif (!sprite || !sprite.frames[0]) continue;\n\n\t\t\t\tif (sprite.frames.length > 1) {\n\t\t\t\t\tqueueAnimatedTile(this.renderState, sprite, this.block_width, this.block_height, i, j, parsed);\n\t\t\t\t} else {\n\t\t\t\t\tdrawTile(context, sprite, this.block_width, this.block_height, i, j, parsed);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tloadFile(url: string, loaded?: () => void): void {\n\t\tconst req = new XMLHttpRequest();\n\t\treq.onreadystatechange = () => {\n\t\t\tif (req.readyState === XMLHttpRequest.DONE && req.status === 200) {\n\t\t\t\tthis.load(req.responseText, this.sprites);\n\t\t\t\tthis.update();\n\t\t\t\tloaded?.();\n\t\t\t}\n\t\t};\n\t\treq.open(\"GET\", url);\n\t\treq.send();\n\t}\n\n\tload(data: string, sprites: Record<string, Sprite>): void {\n\t\tconst parsed: MapData = JSON.parse(data);\n\t\tthis.width = parsed.width;\n\t\tthis.height = parsed.height;\n\t\tthis.block_width = parsed.block_width;\n\t\tthis.block_height = parsed.block_height;\n\t\tthis.sprites = sprites ?? this.sprites;\n\n\t\tfor (let j = 0; j < parsed.height; j++) {\n\t\t\tfor (let i = 0; i < parsed.width; i++) {\n\t\t\t\tconst idx = i + j * parsed.width;\n\t\t\t\tconst value = parsed.data[idx];\n\t\t\t\tif (value > 0) {\n\t\t\t\t\tconst ref = parsed.sprites[value] as string;\n\t\t\t\t\tthis.map[idx] = ref;\n\t\t\t\t\tthis.parsedMap[idx] = parseTileRef(ref);\n\t\t\t\t} else {\n\t\t\t\t\tthis.map[idx] = null;\n\t\t\t\t\tthis.parsedMap[idx] = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.needs_update = true;\n\t}\n\n\tclone(): TileMap {\n\t\tconst duplicate = new TileMap(this.width, this.height, this.block_width, this.block_height, this.sprites);\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tduplicate.map[idx] = this.map[idx];\n\t\t\t\tduplicate.parsedMap[idx] = this.parsedMap[idx];\n\t\t\t}\n\t\t}\n\t\tduplicate.needs_update = true;\n\t\treturn duplicate;\n\t}\n\n\tcopyFrom(map: TileMap): TileMap {\n\t\tthis.width = map.width;\n\t\tthis.height = map.height;\n\t\tthis.block_width = map.block_width;\n\t\tthis.block_height = map.block_height;\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tthis.map[idx] = map.map[idx];\n\t\t\t\tthis.parsedMap[idx] = map.parsedMap[idx];\n\t\t\t}\n\t\t}\n\t\tthis.update();\n\t\treturn this;\n\t}\n}\n\nexport function LoadMap(url: string, sprites?: Record<string, Sprite>, loaded?: () => void): TileMap {\n\tconst map = new TileMap(1, 1, 1, 1, sprites);\n\tmap.ready = false;\n\n\tconst req = new XMLHttpRequest();\n\treq.onreadystatechange = () => {\n\t\tif (req.readyState === XMLHttpRequest.DONE) {\n\t\t\tmap.ready = true;\n\t\t\tif (req.status === 200) {\n\t\t\t\tUpdateMap(map, req.responseText, sprites);\n\t\t\t}\n\t\t\tmap.needs_update = true;\n\t\t\tloaded?.();\n\t\t}\n\t};\n\treq.open(\"GET\", url);\n\treq.send();\n\treturn map;\n}\n\nexport function UpdateMap(map: TileMap, data: string, sprites?: Record<string, Sprite>): TileMap {\n\tmap.load(data, sprites ?? map.sprites);\n\treturn map;\n}\n\nexport function SaveMap(map: TileMap): string {\n\tlet index = 1;\n\tconst list: Array<string | number> = [0];\n\tconst table: Record<string, number> = {};\n\n\tfor (let j = 0; j < map.height; j++) {\n\t\tfor (let i = 0; i < map.width; i++) {\n\t\t\tconst entry = map.map[i + j * map.width];\n\t\t\tif (entry && entry.length > 0 && table[entry] == null) {\n\t\t\t\tlist.push(entry);\n\t\t\t\ttable[entry] = index++;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst serialized: number[] = [];\n\tfor (let j = 0; j < map.height; j++) {\n\t\tfor (let i = 0; i < map.width; i++) {\n\t\t\tconst entry = map.map[i + j * map.width];\n\t\t\tserialized[i + j * map.width] = entry && entry.length > 0 ? table[entry] : 0;\n\t\t}\n\t}\n\n\tconst payload: MapData = {\n\t\twidth: map.width,\n\t\theight: map.height,\n\t\tblock_width: map.block_width,\n\t\tblock_height: map.block_height,\n\t\tsprites: list,\n\t\tdata: serialized,\n\t};\n\n\treturn JSON.stringify(payload);\n}\n","import { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { AnimatedTile, ParsedTile } from \"../data/types\";\n\nexport interface RenderState {\n\tcanvas: HTMLCanvasElement | null;\n\tbuffer: HTMLCanvasElement | null;\n\tanimated: AnimatedTile[];\n}\n\nexport const ensureCanvas = (\n\tstate: RenderState,\n\twidth: number,\n\theight: number,\n\tblockWidth: number,\n\tblockHeight: number,\n): CanvasRenderingContext2D => {\n\tif (!state.canvas) {\n\t\tstate.canvas = document.createElement(\"canvas\");\n\t}\n\tconst expectedWidth = width * blockWidth;\n\tconst expectedHeight = height * blockHeight;\n\tif (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {\n\t\tstate.canvas.width = expectedWidth;\n\t\tstate.canvas.height = expectedHeight;\n\t}\n\tconst ctx = state.canvas.getContext(\"2d\");\n\tif (!ctx) {\n\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7031);\n\t\tconst formatted = formatForBrowser(diagnostic);\n\t\tthrow new Error(formatted);\n\t}\n\tctx.clearRect(0, 0, state.canvas.width, state.canvas.height);\n\tstate.animated = [];\n\treturn ctx;\n};\n\nexport const drawTile = (\n\tctx: CanvasRenderingContext2D,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): boolean => {\n\tconst canvas = sprite.frames[0].canvas;\n\tif (!canvas || canvas.width === 0 || canvas.height === 0) {\n\t\treturn false;\n\t}\n\tif (parsed.subX != null) {\n\t\tconst tx = parsed.subX * blockWidth;\n\t\tconst ty = (parsed.subY ?? 0) * blockHeight;\n\t\tctx.drawImage(\n\t\t\tcanvas,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t\tblockWidth * gridX,\n\t\t\tblockHeight * gridY,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t);\n\t} else {\n\t\tctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);\n\t}\n\treturn true;\n};\n\nexport const queueAnimatedTile = (\n\tstate: RenderState,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): void => {\n\tconst tile: AnimatedTile = {\n\t\tx: blockWidth * gridX,\n\t\ty: blockHeight * gridY,\n\t\tw: blockWidth,\n\t\th: blockHeight,\n\t\tsprite,\n\t};\n\tif (parsed.subX != null) {\n\t\ttile.tx = parsed.subX * blockWidth;\n\t\ttile.ty = (parsed.subY ?? 0) * blockHeight;\n\t}\n\tstate.animated.push(tile);\n};\n\nexport const renderAnimatedTiles = (state: RenderState, blockWidth: number, blockHeight: number): HTMLCanvasElement => {\n\tconst time = performance.now();\n\tif (\n\t\t!state.buffer ||\n\t\tstate.buffer.width !== blockWidth * (state.canvas!.width / blockWidth) ||\n\t\tstate.buffer.height !== blockHeight * (state.canvas!.height / blockHeight)\n\t) {\n\t\tstate.buffer = document.createElement(\"canvas\");\n\t\tstate.buffer.width = state.canvas!.width;\n\t\tstate.buffer.height = state.canvas!.height;\n\t}\n\tconst bufferCtx = state.buffer.getContext(\"2d\")!;\n\tbufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);\n\tbufferCtx.drawImage(state.canvas!, 0, 0);\n\tfor (const tile of state.animated) {\n\t\tconst len = tile.sprite.frames.length;\n\t\tconst frame = tile.sprite.frames[Math.floor((time / 1000) * tile.sprite.fps) % len]?.canvas;\n\t\tif (!frame) continue;\n\t\tif (tile.tx != null && tile.ty != null) {\n\t\t\tbufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);\n\t\t} else {\n\t\t\tbufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);\n\t\t}\n\t}\n\treturn state.buffer;\n};\n","// Convert forward slashes to dashes for safe storage in map data format\nexport const normalizeRefForStorage = (ref: string): string => ref.replace(/\\//g, \"-\");\n// Convert dashes back to forward slashes for sprite reference lookup\nexport const normalizeRefForUsage = (ref: string): string => ref.replace(/-/g, \"/\");\n"],"mappings":"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","names":["import_diagnostics","ensureCanvas","state","width","height","blockWidth","blockHeight","canvas","document","createElement","expectedWidth","expectedHeight","ctx","getContext","diagnostic","createDiagnostic","APIErrorCode","E7031","formatted","formatForBrowser","Error","clearRect","animated","drawTile","sprite","gridX","gridY","parsed","frames","subX","tx","ty","subY","drawImage","queueAnimatedTile","tile","x","y","w","h","push","renderAnimatedTiles","time","performance","now","buffer","bufferCtx","len","length","frame","Math","floor","fps","normalizeRefForStorage","ref","replace","normalizeRefForUsage","parseTileRef","entry","colonIdx","indexOf","spriteName","substring","coords","commaIdx","subX","Number","parseInt","subY","TileMap","width","height","block_width","block_height","sprites","map","ready","needs_update","name","parsedMap","renderState","canvas","buffer","animated","isFinite","diagnostic","createDiagnostic","APIErrorCode","E7034","data","formatted","formatForBrowser","Error","clear","j","i","idx","set","x","y","ref","normalized","normalizeRefForStorage","get","cell","normalizeRefForUsage","getCanvas","update","draw","context","w","h","length","renderAnimatedTiles","drawImage","ensureCanvas","index","parsed","sprite","frames","queueAnimatedTile","drawTile","loadFile","url","loaded","req","XMLHttpRequest","onreadystatechange","readyState","DONE","status","load","responseText","open","send","JSON","parse","value","clone","duplicate","copyFrom","LoadMap","UpdateMap","SaveMap","list","table","push","serialized","payload","stringify"]}
|