lpc-forge 1.0.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/CREDITS.csv +22985 -0
- package/LICENSE +674 -0
- package/README.md +281 -0
- package/assets/music/.gitkeep +0 -0
- package/dist/character/batch.d.ts +17 -0
- package/dist/character/batch.js +48 -0
- package/dist/character/batch.js.map +1 -0
- package/dist/character/composer.d.ts +3 -0
- package/dist/character/composer.js +164 -0
- package/dist/character/composer.js.map +1 -0
- package/dist/character/definitions.d.ts +16 -0
- package/dist/character/definitions.js +116 -0
- package/dist/character/definitions.js.map +1 -0
- package/dist/character/presets.d.ts +6 -0
- package/dist/character/presets.js +246 -0
- package/dist/character/presets.js.map +1 -0
- package/dist/character/slicer.d.ts +8 -0
- package/dist/character/slicer.js +66 -0
- package/dist/character/slicer.js.map +1 -0
- package/dist/character/types.d.ts +48 -0
- package/dist/character/types.js +32 -0
- package/dist/character/types.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +938 -0
- package/dist/export/frames.d.ts +5 -0
- package/dist/export/frames.js +15 -0
- package/dist/export/frames.js.map +1 -0
- package/dist/export/godot.d.ts +17 -0
- package/dist/export/godot.js +464 -0
- package/dist/export/godot.js.map +1 -0
- package/dist/export/types.d.ts +11 -0
- package/dist/export/types.js +2 -0
- package/dist/export/types.js.map +1 -0
- package/dist/license.d.ts +49 -0
- package/dist/license.js +271 -0
- package/dist/map/cellular.d.ts +3 -0
- package/dist/map/cellular.js +191 -0
- package/dist/map/cellular.js.map +1 -0
- package/dist/map/dungeon.d.ts +3 -0
- package/dist/map/dungeon.js +238 -0
- package/dist/map/dungeon.js.map +1 -0
- package/dist/map/multifloor.d.ts +20 -0
- package/dist/map/multifloor.js +57 -0
- package/dist/map/multifloor.js.map +1 -0
- package/dist/map/overworld.d.ts +3 -0
- package/dist/map/overworld.js +205 -0
- package/dist/map/overworld.js.map +1 -0
- package/dist/map/town.d.ts +7 -0
- package/dist/map/town.js +181 -0
- package/dist/map/town.js.map +1 -0
- package/dist/map/types.d.ts +65 -0
- package/dist/map/types.js +16 -0
- package/dist/map/types.js.map +1 -0
- package/dist/map/wfc.d.ts +18 -0
- package/dist/map/wfc.js +192 -0
- package/dist/map/wfc.js.map +1 -0
- package/dist/tileset/atlas.d.ts +15 -0
- package/dist/tileset/atlas.js +55 -0
- package/dist/tileset/atlas.js.map +1 -0
- package/dist/tileset/registry.d.ts +12 -0
- package/dist/tileset/registry.js +71 -0
- package/dist/tileset/registry.js.map +1 -0
- package/dist/tileset/terrain.d.ts +3 -0
- package/dist/tileset/terrain.js +110 -0
- package/dist/tileset/terrain.js.map +1 -0
- package/dist/utils/credits.d.ts +11 -0
- package/dist/utils/credits.js +74 -0
- package/dist/utils/credits.js.map +1 -0
- package/dist/utils/image.d.ts +17 -0
- package/dist/utils/image.js +94 -0
- package/dist/utils/image.js.map +1 -0
- package/dist/utils/rng.d.ts +18 -0
- package/dist/utils/rng.js +48 -0
- package/dist/utils/rng.js.map +1 -0
- package/package.json +77 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { mkdir, writeFile, readFile, access } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { TileType } from '../map/types.js';
|
|
4
|
+
import { createColorTile } from '../utils/image.js';
|
|
5
|
+
const DEFAULT_TILE_SIZE = 32;
|
|
6
|
+
/** Tile color definitions for procedural generation */
|
|
7
|
+
const TILE_COLORS = {
|
|
8
|
+
floor: { r: 180, g: 150, b: 110, border: { r: 160, g: 130, b: 90 } },
|
|
9
|
+
wall: { r: 80, g: 80, b: 90, border: { r: 60, g: 60, b: 70 } },
|
|
10
|
+
wall_top: { r: 100, g: 100, b: 110, border: { r: 70, g: 70, b: 80 } },
|
|
11
|
+
door: { r: 140, g: 100, b: 60, border: { r: 100, g: 70, b: 40 } },
|
|
12
|
+
corridor: { r: 160, g: 135, b: 100, border: { r: 140, g: 115, b: 80 } },
|
|
13
|
+
water: { r: 60, g: 120, b: 190, border: { r: 40, g: 100, b: 170 } },
|
|
14
|
+
grass: { r: 80, g: 160, b: 60, border: { r: 60, g: 140, b: 40 } },
|
|
15
|
+
tree: { r: 30, g: 100, b: 30, border: { r: 20, g: 80, b: 20 } },
|
|
16
|
+
path: { r: 190, g: 170, b: 130, border: { r: 170, g: 150, b: 110 } },
|
|
17
|
+
sand: { r: 220, g: 200, b: 140, border: { r: 200, g: 180, b: 120 } },
|
|
18
|
+
stone: { r: 140, g: 140, b: 150, border: { r: 120, g: 120, b: 130 } },
|
|
19
|
+
bridge: { r: 150, g: 110, b: 70, border: { r: 130, g: 90, b: 50 } },
|
|
20
|
+
void: { r: 0, g: 0, b: 0 },
|
|
21
|
+
};
|
|
22
|
+
/** Generate default placeholder tiles programmatically */
|
|
23
|
+
export async function generateDefaultTileset(outputDir) {
|
|
24
|
+
await mkdir(outputDir, { recursive: true });
|
|
25
|
+
const manifest = {
|
|
26
|
+
name: 'default',
|
|
27
|
+
tileSize: DEFAULT_TILE_SIZE,
|
|
28
|
+
tiles: {},
|
|
29
|
+
};
|
|
30
|
+
for (const [name, color] of Object.entries(TILE_COLORS)) {
|
|
31
|
+
const fileName = `${name}.png`;
|
|
32
|
+
const filePath = join(outputDir, fileName);
|
|
33
|
+
const buffer = await createColorTile(DEFAULT_TILE_SIZE, color.r, color.g, color.b, name === 'void' ? 0 : 255, color.border);
|
|
34
|
+
await writeFile(filePath, buffer);
|
|
35
|
+
manifest.tiles[name.toUpperCase()] = fileName;
|
|
36
|
+
}
|
|
37
|
+
await writeFile(join(outputDir, 'tileset.json'), JSON.stringify(manifest, null, 2));
|
|
38
|
+
return manifest;
|
|
39
|
+
}
|
|
40
|
+
/** Load a tileset manifest from a directory */
|
|
41
|
+
export async function loadTileset(tilesetDir) {
|
|
42
|
+
const manifestPath = join(tilesetDir, 'tileset.json');
|
|
43
|
+
try {
|
|
44
|
+
await access(manifestPath);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Generate default tileset if it doesn't exist
|
|
48
|
+
return generateDefaultTileset(tilesetDir);
|
|
49
|
+
}
|
|
50
|
+
const content = await readFile(manifestPath, 'utf-8');
|
|
51
|
+
return JSON.parse(content);
|
|
52
|
+
}
|
|
53
|
+
/** Map TileType enum to tile name */
|
|
54
|
+
export function tileTypeToName(t) {
|
|
55
|
+
const mapping = {
|
|
56
|
+
[TileType.VOID]: 'VOID',
|
|
57
|
+
[TileType.FLOOR]: 'FLOOR',
|
|
58
|
+
[TileType.WALL]: 'WALL',
|
|
59
|
+
[TileType.DOOR]: 'DOOR',
|
|
60
|
+
[TileType.CORRIDOR]: 'CORRIDOR',
|
|
61
|
+
[TileType.WATER]: 'WATER',
|
|
62
|
+
[TileType.GRASS]: 'GRASS',
|
|
63
|
+
[TileType.TREE]: 'TREE',
|
|
64
|
+
[TileType.PATH]: 'PATH',
|
|
65
|
+
[TileType.SAND]: 'SAND',
|
|
66
|
+
[TileType.STONE]: 'STONE',
|
|
67
|
+
[TileType.BRIDGE]: 'BRIDGE',
|
|
68
|
+
};
|
|
69
|
+
return mapping[t] ?? 'VOID';
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tileset/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
import { readFile, writeFile, mkdir } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { loadTileset, tileTypeToName } from './registry.js';
|
|
5
|
+
/** Render a GeneratedMap into a visual PNG */
|
|
6
|
+
export async function renderMap(map, tilesetDir, outputPath) {
|
|
7
|
+
const manifest = await loadTileset(tilesetDir);
|
|
8
|
+
const tileSize = manifest.tileSize;
|
|
9
|
+
const canvasWidth = map.width * tileSize;
|
|
10
|
+
const canvasHeight = map.height * tileSize;
|
|
11
|
+
// Pre-load all tile images
|
|
12
|
+
const tileBuffers = {};
|
|
13
|
+
for (const [name, fileName] of Object.entries(manifest.tiles)) {
|
|
14
|
+
try {
|
|
15
|
+
const buf = await readFile(join(tilesetDir, fileName));
|
|
16
|
+
tileBuffers[name] = buf;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
// Skip missing tiles
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Build composites for each tile
|
|
23
|
+
const composites = [];
|
|
24
|
+
for (let y = 0; y < map.height; y++) {
|
|
25
|
+
for (let x = 0; x < map.width; x++) {
|
|
26
|
+
const tileType = map.tiles[y][x];
|
|
27
|
+
const tileName = tileTypeToName(tileType);
|
|
28
|
+
const buf = tileBuffers[tileName];
|
|
29
|
+
if (buf) {
|
|
30
|
+
composites.push({
|
|
31
|
+
input: buf,
|
|
32
|
+
top: y * tileSize,
|
|
33
|
+
left: x * tileSize,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// Sharp has a practical limit on composites, batch if needed
|
|
39
|
+
await mkdir(join(outputPath, '..'), { recursive: true });
|
|
40
|
+
// If map is large, render in row strips
|
|
41
|
+
if (composites.length > 5000) {
|
|
42
|
+
await renderInStrips(map, tileBuffers, tileSize, canvasWidth, canvasHeight, outputPath);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const result = await sharp({
|
|
46
|
+
create: {
|
|
47
|
+
width: canvasWidth,
|
|
48
|
+
height: canvasHeight,
|
|
49
|
+
channels: 4,
|
|
50
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
51
|
+
},
|
|
52
|
+
})
|
|
53
|
+
.png()
|
|
54
|
+
.composite(composites)
|
|
55
|
+
.toBuffer();
|
|
56
|
+
await writeFile(outputPath, result);
|
|
57
|
+
}
|
|
58
|
+
async function renderInStrips(map, tileBuffers, tileSize, canvasWidth, canvasHeight, outputPath) {
|
|
59
|
+
const stripHeight = 10; // rows per strip
|
|
60
|
+
const strips = [];
|
|
61
|
+
for (let startRow = 0; startRow < map.height; startRow += stripHeight) {
|
|
62
|
+
const endRow = Math.min(startRow + stripHeight, map.height);
|
|
63
|
+
const stripPixelH = (endRow - startRow) * tileSize;
|
|
64
|
+
const composites = [];
|
|
65
|
+
for (let y = startRow; y < endRow; y++) {
|
|
66
|
+
for (let x = 0; x < map.width; x++) {
|
|
67
|
+
const tileName = tileTypeToName(map.tiles[y][x]);
|
|
68
|
+
const buf = tileBuffers[tileName];
|
|
69
|
+
if (buf) {
|
|
70
|
+
composites.push({
|
|
71
|
+
input: buf,
|
|
72
|
+
top: (y - startRow) * tileSize,
|
|
73
|
+
left: x * tileSize,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const stripBuf = await sharp({
|
|
79
|
+
create: {
|
|
80
|
+
width: canvasWidth,
|
|
81
|
+
height: stripPixelH,
|
|
82
|
+
channels: 4,
|
|
83
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
84
|
+
},
|
|
85
|
+
})
|
|
86
|
+
.png()
|
|
87
|
+
.composite(composites)
|
|
88
|
+
.toBuffer();
|
|
89
|
+
strips.push(stripBuf);
|
|
90
|
+
}
|
|
91
|
+
// Stitch strips vertically
|
|
92
|
+
const stitchComposites = strips.map((buf, i) => ({
|
|
93
|
+
input: buf,
|
|
94
|
+
top: i * stripHeight * tileSize,
|
|
95
|
+
left: 0,
|
|
96
|
+
}));
|
|
97
|
+
const final = await sharp({
|
|
98
|
+
create: {
|
|
99
|
+
width: canvasWidth,
|
|
100
|
+
height: canvasHeight,
|
|
101
|
+
channels: 4,
|
|
102
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
103
|
+
},
|
|
104
|
+
})
|
|
105
|
+
.png()
|
|
106
|
+
.composite(stitchComposites)
|
|
107
|
+
.toBuffer();
|
|
108
|
+
await writeFile(outputPath, final);
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=terrain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terrain.js","sourceRoot":"","sources":["../../src/tileset/terrain.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,cAAc,EAAwB,MAAM,eAAe,CAAC;AAElF,8CAA8C;AAC9C,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,GAAiB,EACjB,UAAkB,EAClB,UAAkB;IAElB,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC;IACnC,MAAM,WAAW,GAAG,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC;IACzC,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC;IAE3C,2BAA2B;IAC3B,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;YACvD,WAAW,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,qBAAqB;QACvB,CAAC;IACH,CAAC;IAED,iCAAiC;IACjC,MAAM,UAAU,GAA2B,EAAE,CAAC;IAE9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;YAElC,IAAI,GAAG,EAAE,CAAC;gBACR,UAAU,CAAC,IAAI,CAAC;oBACd,KAAK,EAAE,GAAG;oBACV,GAAG,EAAE,CAAC,GAAG,QAAQ;oBACjB,IAAI,EAAE,CAAC,GAAG,QAAQ;iBACnB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;IACH,CAAC;IAED,6DAA6D;IAC7D,MAAM,KAAK,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,wCAAwC;IACxC,IAAI,UAAU,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;QAC7B,MAAM,cAAc,CAAC,GAAG,EAAE,WAAW,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACxF,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC;QACzB,MAAM,EAAE;YACN,KAAK,EAAE,WAAW;YAClB,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;SAC3C;KACF,CAAC;SACC,GAAG,EAAE;SACL,SAAS,CAAC,UAAU,CAAC;SACrB,QAAQ,EAAE,CAAC;IAEd,MAAM,SAAS,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,KAAK,UAAU,cAAc,CAC3B,GAAiB,EACjB,WAAmC,EACnC,QAAgB,EAChB,WAAmB,EACnB,YAAoB,EACpB,UAAkB;IAElB,MAAM,WAAW,GAAG,EAAE,CAAC,CAAC,iBAAiB;IACzC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,QAAQ,IAAI,WAAW,EAAE,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,QAAQ,CAAC;QACnD,MAAM,UAAU,GAA2B,EAAE,CAAC;QAE9C,KAAK,IAAI,CAAC,GAAG,QAAQ,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnC,MAAM,QAAQ,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACjD,MAAM,GAAG,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAClC,IAAI,GAAG,EAAE,CAAC;oBACR,UAAU,CAAC,IAAI,CAAC;wBACd,KAAK,EAAE,GAAG;wBACV,GAAG,EAAE,CAAC,CAAC,GAAG,QAAQ,CAAC,GAAG,QAAQ;wBAC9B,IAAI,EAAE,CAAC,GAAG,QAAQ;qBACnB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC;YAC3B,MAAM,EAAE;gBACN,KAAK,EAAE,WAAW;gBAClB,MAAM,EAAE,WAAW;gBACnB,QAAQ,EAAE,CAAC;gBACX,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;aAC3C;SACF,CAAC;aACC,GAAG,EAAE;aACL,SAAS,CAAC,UAAU,CAAC;aACrB,QAAQ,EAAE,CAAC;QAEd,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxB,CAAC;IAED,2BAA2B;IAC3B,MAAM,gBAAgB,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC/C,KAAK,EAAE,GAAG;QACV,GAAG,EAAE,CAAC,GAAG,WAAW,GAAG,QAAQ;QAC/B,IAAI,EAAE,CAAC;KACR,CAAC,CAAC,CAAC;IAEJ,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC;QACxB,MAAM,EAAE;YACN,KAAK,EAAE,WAAW;YAClB,MAAM,EAAE,YAAY;YACpB,QAAQ,EAAE,CAAC;YACX,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;SAC3C;KACF,CAAC;SACC,GAAG,EAAE;SACL,SAAS,CAAC,gBAAgB,CAAC;SAC3B,QAAQ,EAAE,CAAC;IAEd,MAAM,SAAS,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CreditEntry {
|
|
2
|
+
file: string;
|
|
3
|
+
authors: string[];
|
|
4
|
+
licenses: string[];
|
|
5
|
+
urls: string[];
|
|
6
|
+
notes?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Parse CREDITS.csv and return structured credit entries */
|
|
9
|
+
export declare function parseCredits(repoRoot: string): Promise<CreditEntry[]>;
|
|
10
|
+
/** Generate a credits text file for used layers */
|
|
11
|
+
export declare function generateCreditsText(credits: CreditEntry[], usedPaths: string[]): string;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/** Parse CREDITS.csv and return structured credit entries */
|
|
4
|
+
export async function parseCredits(repoRoot) {
|
|
5
|
+
const csvPath = join(repoRoot, 'CREDITS.csv');
|
|
6
|
+
const content = await readFile(csvPath, 'utf-8');
|
|
7
|
+
const lines = content.split('\n');
|
|
8
|
+
if (lines.length < 2)
|
|
9
|
+
return [];
|
|
10
|
+
const entries = [];
|
|
11
|
+
// Skip header row
|
|
12
|
+
for (let i = 1; i < lines.length; i++) {
|
|
13
|
+
const line = lines[i].trim();
|
|
14
|
+
if (!line)
|
|
15
|
+
continue;
|
|
16
|
+
const cols = parseCSVLine(line);
|
|
17
|
+
if (cols.length < 4)
|
|
18
|
+
continue;
|
|
19
|
+
entries.push({
|
|
20
|
+
file: cols[0],
|
|
21
|
+
authors: cols[1] ? cols[1].split(',').map((a) => a.trim()) : [],
|
|
22
|
+
licenses: cols[2] ? cols[2].split(',').map((l) => l.trim()) : [],
|
|
23
|
+
urls: cols[3] ? cols[3].split(',').map((u) => u.trim()) : [],
|
|
24
|
+
notes: cols[4] || undefined,
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return entries;
|
|
28
|
+
}
|
|
29
|
+
function parseCSVLine(line) {
|
|
30
|
+
const result = [];
|
|
31
|
+
let current = '';
|
|
32
|
+
let inQuotes = false;
|
|
33
|
+
for (let i = 0; i < line.length; i++) {
|
|
34
|
+
const ch = line[i];
|
|
35
|
+
if (ch === '"') {
|
|
36
|
+
if (inQuotes && line[i + 1] === '"') {
|
|
37
|
+
current += '"';
|
|
38
|
+
i++;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
inQuotes = !inQuotes;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else if (ch === ',' && !inQuotes) {
|
|
45
|
+
result.push(current.trim());
|
|
46
|
+
current = '';
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
current += ch;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
result.push(current.trim());
|
|
53
|
+
return result;
|
|
54
|
+
}
|
|
55
|
+
/** Generate a credits text file for used layers */
|
|
56
|
+
export function generateCreditsText(credits, usedPaths) {
|
|
57
|
+
const relevant = credits.filter((c) => usedPaths.some((p) => p.includes(c.file) || c.file.includes(p)));
|
|
58
|
+
if (relevant.length === 0) {
|
|
59
|
+
return 'Credits: Based on Liberated Pixel Cup (LPC) assets. See CREDITS.csv for full attribution.\n';
|
|
60
|
+
}
|
|
61
|
+
const lines = ['=== Asset Credits ===', ''];
|
|
62
|
+
for (const entry of relevant) {
|
|
63
|
+
lines.push(`File: ${entry.file}`);
|
|
64
|
+
lines.push(`Authors: ${entry.authors.join(', ')}`);
|
|
65
|
+
lines.push(`Licenses: ${entry.licenses.join(', ')}`);
|
|
66
|
+
if (entry.urls.length > 0) {
|
|
67
|
+
lines.push(`URLs: ${entry.urls.join(', ')}`);
|
|
68
|
+
}
|
|
69
|
+
lines.push('');
|
|
70
|
+
}
|
|
71
|
+
lines.push('Full credits available in CREDITS.csv');
|
|
72
|
+
return lines.join('\n');
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=credits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credits.js","sourceRoot":"","sources":["../../src/utils/credits.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/** Create a transparent RGBA canvas of the given size */
|
|
2
|
+
export declare function createCanvas(width: number, height: number): Promise<Buffer>;
|
|
3
|
+
/** Composite multiple image buffers onto a base, all at full size */
|
|
4
|
+
export declare function compositeLayers(width: number, height: number, layers: Buffer[]): Promise<Buffer>;
|
|
5
|
+
/** Stitch multiple images vertically into one tall image */
|
|
6
|
+
export declare function stitchVertical(images: {
|
|
7
|
+
buffer: Buffer;
|
|
8
|
+
yOffset: number;
|
|
9
|
+
}[], totalWidth: number, totalHeight: number): Promise<Buffer>;
|
|
10
|
+
/** Extract a rectangular region from an image buffer */
|
|
11
|
+
export declare function extractRegion(buffer: Buffer, left: number, top: number, width: number, height: number): Promise<Buffer>;
|
|
12
|
+
/** Create a solid-color tile with optional border */
|
|
13
|
+
export declare function createColorTile(size: number, r: number, g: number, b: number, alpha?: number, borderColor?: {
|
|
14
|
+
r: number;
|
|
15
|
+
g: number;
|
|
16
|
+
b: number;
|
|
17
|
+
}): Promise<Buffer>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import sharp from 'sharp';
|
|
2
|
+
/** Create a transparent RGBA canvas of the given size */
|
|
3
|
+
export async function createCanvas(width, height) {
|
|
4
|
+
return sharp({
|
|
5
|
+
create: {
|
|
6
|
+
width,
|
|
7
|
+
height,
|
|
8
|
+
channels: 4,
|
|
9
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
10
|
+
},
|
|
11
|
+
})
|
|
12
|
+
.png()
|
|
13
|
+
.toBuffer();
|
|
14
|
+
}
|
|
15
|
+
/** Composite multiple image buffers onto a base, all at full size */
|
|
16
|
+
export async function compositeLayers(width, height, layers) {
|
|
17
|
+
if (layers.length === 0) {
|
|
18
|
+
return createCanvas(width, height);
|
|
19
|
+
}
|
|
20
|
+
const composites = layers.map((input) => ({
|
|
21
|
+
input,
|
|
22
|
+
top: 0,
|
|
23
|
+
left: 0,
|
|
24
|
+
blend: 'over',
|
|
25
|
+
}));
|
|
26
|
+
return sharp({
|
|
27
|
+
create: {
|
|
28
|
+
width,
|
|
29
|
+
height,
|
|
30
|
+
channels: 4,
|
|
31
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
.png()
|
|
35
|
+
.composite(composites)
|
|
36
|
+
.toBuffer();
|
|
37
|
+
}
|
|
38
|
+
/** Stitch multiple images vertically into one tall image */
|
|
39
|
+
export async function stitchVertical(images, totalWidth, totalHeight) {
|
|
40
|
+
const composites = images.map(({ buffer, yOffset }) => ({
|
|
41
|
+
input: buffer,
|
|
42
|
+
top: yOffset,
|
|
43
|
+
left: 0,
|
|
44
|
+
blend: 'over',
|
|
45
|
+
}));
|
|
46
|
+
return sharp({
|
|
47
|
+
create: {
|
|
48
|
+
width: totalWidth,
|
|
49
|
+
height: totalHeight,
|
|
50
|
+
channels: 4,
|
|
51
|
+
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
.png()
|
|
55
|
+
.composite(composites)
|
|
56
|
+
.toBuffer();
|
|
57
|
+
}
|
|
58
|
+
/** Extract a rectangular region from an image buffer */
|
|
59
|
+
export async function extractRegion(buffer, left, top, width, height) {
|
|
60
|
+
return sharp(buffer).extract({ left, top, width, height }).png().toBuffer();
|
|
61
|
+
}
|
|
62
|
+
/** Create a solid-color tile with optional border */
|
|
63
|
+
export async function createColorTile(size, r, g, b, alpha = 255, borderColor) {
|
|
64
|
+
// Create the fill
|
|
65
|
+
const base = await sharp({
|
|
66
|
+
create: {
|
|
67
|
+
width: size,
|
|
68
|
+
height: size,
|
|
69
|
+
channels: 4,
|
|
70
|
+
background: { r, g, b, alpha },
|
|
71
|
+
},
|
|
72
|
+
})
|
|
73
|
+
.png()
|
|
74
|
+
.toBuffer();
|
|
75
|
+
if (!borderColor)
|
|
76
|
+
return base;
|
|
77
|
+
// Overlay a 1px border by creating border lines
|
|
78
|
+
const hLine = await sharp({
|
|
79
|
+
create: { width: size, height: 1, channels: 4, background: { ...borderColor, alpha: 255 } },
|
|
80
|
+
}).png().toBuffer();
|
|
81
|
+
const vLine = await sharp({
|
|
82
|
+
create: { width: 1, height: size, channels: 4, background: { ...borderColor, alpha: 255 } },
|
|
83
|
+
}).png().toBuffer();
|
|
84
|
+
return sharp(base)
|
|
85
|
+
.composite([
|
|
86
|
+
{ input: hLine, top: 0, left: 0 },
|
|
87
|
+
{ input: hLine, top: size - 1, left: 0 },
|
|
88
|
+
{ input: vLine, top: 0, left: 0 },
|
|
89
|
+
{ input: vLine, top: 0, left: size - 1 },
|
|
90
|
+
])
|
|
91
|
+
.png()
|
|
92
|
+
.toBuffer();
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=image.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image.js","sourceRoot":"","sources":["../../src/utils/image.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded pseudo-random number generator using mulberry32.
|
|
3
|
+
*/
|
|
4
|
+
export declare class SeededRNG {
|
|
5
|
+
private state;
|
|
6
|
+
constructor(seed: string | number);
|
|
7
|
+
private hashString;
|
|
8
|
+
/** Returns a float in [0, 1) */
|
|
9
|
+
random(): number;
|
|
10
|
+
/** Returns an integer in [min, max] (inclusive) */
|
|
11
|
+
randomInt(min: number, max: number): number;
|
|
12
|
+
/** Returns a float in [min, max) */
|
|
13
|
+
randomFloat(min: number, max: number): number;
|
|
14
|
+
/** Fisher-Yates shuffle (in-place) */
|
|
15
|
+
shuffle<T>(array: T[]): T[];
|
|
16
|
+
/** Pick a random element from an array */
|
|
17
|
+
pick<T>(array: readonly T[]): T;
|
|
18
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded pseudo-random number generator using mulberry32.
|
|
3
|
+
*/
|
|
4
|
+
export class SeededRNG {
|
|
5
|
+
state;
|
|
6
|
+
constructor(seed) {
|
|
7
|
+
this.state = typeof seed === 'string' ? this.hashString(seed) : seed;
|
|
8
|
+
if (this.state === 0)
|
|
9
|
+
this.state = 1;
|
|
10
|
+
}
|
|
11
|
+
hashString(s) {
|
|
12
|
+
let hash = 0;
|
|
13
|
+
for (let i = 0; i < s.length; i++) {
|
|
14
|
+
const ch = s.charCodeAt(i);
|
|
15
|
+
hash = ((hash << 5) - hash + ch) | 0;
|
|
16
|
+
}
|
|
17
|
+
return Math.abs(hash) || 1;
|
|
18
|
+
}
|
|
19
|
+
/** Returns a float in [0, 1) */
|
|
20
|
+
random() {
|
|
21
|
+
this.state |= 0;
|
|
22
|
+
this.state = (this.state + 0x6d2b79f5) | 0;
|
|
23
|
+
let t = Math.imul(this.state ^ (this.state >>> 15), 1 | this.state);
|
|
24
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
25
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
26
|
+
}
|
|
27
|
+
/** Returns an integer in [min, max] (inclusive) */
|
|
28
|
+
randomInt(min, max) {
|
|
29
|
+
return Math.floor(this.random() * (max - min + 1)) + min;
|
|
30
|
+
}
|
|
31
|
+
/** Returns a float in [min, max) */
|
|
32
|
+
randomFloat(min, max) {
|
|
33
|
+
return this.random() * (max - min) + min;
|
|
34
|
+
}
|
|
35
|
+
/** Fisher-Yates shuffle (in-place) */
|
|
36
|
+
shuffle(array) {
|
|
37
|
+
for (let i = array.length - 1; i > 0; i--) {
|
|
38
|
+
const j = this.randomInt(0, i);
|
|
39
|
+
[array[i], array[j]] = [array[j], array[i]];
|
|
40
|
+
}
|
|
41
|
+
return array;
|
|
42
|
+
}
|
|
43
|
+
/** Pick a random element from an array */
|
|
44
|
+
pick(array) {
|
|
45
|
+
return array[this.randomInt(0, array.length - 1)];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=rng.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rng.js","sourceRoot":"","sources":["../../src/utils/rng.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,SAAS;IACZ,KAAK,CAAS;IAEtB,YAAY,IAAqB;QAC/B,IAAI,CAAC,KAAK,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACrE,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC;YAAE,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACvC,CAAC;IAEO,UAAU,CAAC,CAAS;QAC1B,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YAC3B,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC;QACvC,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAED,gCAAgC;IAChC,MAAM;QACJ,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QACpE,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QAC/C,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC;IAC/C,CAAC;IAED,mDAAmD;IACnD,SAAS,CAAC,GAAW,EAAE,GAAW;QAChC,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;IAC3D,CAAC;IAED,oCAAoC;IACpC,WAAW,CAAC,GAAW,EAAE,GAAW;QAClC,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAC3C,CAAC;IAED,sCAAsC;IACtC,OAAO,CAAI,KAAU;QACnB,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC/B,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,0CAA0C;IAC1C,IAAI,CAAI,KAAmB;QACzB,OAAO,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;CACF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lpc-forge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Complete 2D RPG asset pipeline — character compositor, procedural map generator, and Godot 4.6 exporter. Built on Liberated Pixel Cup sprites.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"lpc-forge": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/cli.js",
|
|
11
|
+
"dist/cli.d.ts",
|
|
12
|
+
"dist/character/**",
|
|
13
|
+
"dist/map/**",
|
|
14
|
+
"dist/export/**",
|
|
15
|
+
"dist/tileset/**",
|
|
16
|
+
"dist/utils/**",
|
|
17
|
+
"dist/license.js",
|
|
18
|
+
"dist/license.d.ts",
|
|
19
|
+
"assets/**",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE",
|
|
22
|
+
"CREDITS.csv",
|
|
23
|
+
"package.json"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc",
|
|
27
|
+
"dev": "tsx src/cli.ts",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"lint": "eslint src/"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"lpc",
|
|
33
|
+
"liberated-pixel-cup",
|
|
34
|
+
"spritesheet",
|
|
35
|
+
"character-generator",
|
|
36
|
+
"godot",
|
|
37
|
+
"godot-4",
|
|
38
|
+
"gamedev",
|
|
39
|
+
"pixel-art",
|
|
40
|
+
"rpg",
|
|
41
|
+
"2d",
|
|
42
|
+
"procedural-generation",
|
|
43
|
+
"dungeon-generator",
|
|
44
|
+
"tilemap",
|
|
45
|
+
"indie-game",
|
|
46
|
+
"game-assets",
|
|
47
|
+
"sprite-compositor"
|
|
48
|
+
],
|
|
49
|
+
"author": "LaunchDay Studio <info@launchdaystudio.com> (https://blueth.online)",
|
|
50
|
+
"license": "GPL-3.0-or-later",
|
|
51
|
+
"repository": {
|
|
52
|
+
"type": "git",
|
|
53
|
+
"url": "https://github.com/LaunchDay-Studio-Inc/lpc-forge.git"
|
|
54
|
+
},
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/LaunchDay-Studio-Inc/lpc-forge/issues"
|
|
57
|
+
},
|
|
58
|
+
"homepage": "https://blueth.online",
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=22"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"chalk": "^5.4.0",
|
|
64
|
+
"commander": "^13.0.0",
|
|
65
|
+
"glob": "^11.0.0",
|
|
66
|
+
"jsfxr": "^1.4.0",
|
|
67
|
+
"ora": "^8.2.0",
|
|
68
|
+
"sharp": "^0.34.0"
|
|
69
|
+
},
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"@types/node": "^22.0.0",
|
|
72
|
+
"eslint": "^9.0.0",
|
|
73
|
+
"tsx": "^4.19.0",
|
|
74
|
+
"typescript": "^5.8.0",
|
|
75
|
+
"vitest": "^3.0.0"
|
|
76
|
+
}
|
|
77
|
+
}
|