/**
* Пост-обработка AI-спрайтов «Пепельных лугов» — сценарий над жанронезависимым
* @rpg/engine/tools/imaging.mjs (декодер/кроп/квантизация — там).
* Запуск: node apps/game/tools/aiart/post.mjs <каталог с PNG>
* → рядом ../processed/*.png (кроп по альфе, квантизация в палитру)
* → ../processed/_sheet.png (обзорный лист для апрува)
*
* AI-вывод — только сырьё: в игру попадает после ручного апрува (манифест).
*/
import { readFileSync, writeFileSync, readdirSync, mkdirSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { decodePng, encodePng } from '@rpg/engine/tools/png.mjs';
import { normalizeToSize, quantize, reviewSheet } from '@rpg/engine/tools/imaging.mjs';
import { PALETTE } from '../pixelart/palette.mjs';
const REVIEW = process.argv[2] ?? 'review';
const HERE = fileURLToPath(new URL('.', import.meta.url));
const OUT = join(HERE, 'processed');
const SIZE = 16; // целевой размер спрайта (арт-библия)
/** Палитра игры как массив [r,g,b] для квантизации. */
const PAL = Object.entries(PALETTE).map(([, hex]) => {
const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
});
const names = readdirSync(join(HERE, REVIEW)).filter((f) => f.endsWith('.png'));
mkdirSync(OUT, { recursive: true });
const processed = names.map((name) => {
const img = decodePng(readFileSync(join(HERE, REVIEW, name)));
const rgba = quantize(normalizeToSize(img, SIZE), PAL);
writeFileSync(join(OUT, name), encodePng(SIZE, SIZE, Buffer.from(rgba)));
return { name, rgba };
});
reviewSheet(processed, join(OUT, '_sheet.png'), { size: SIZE });
console.log(`обработано ${processed.length} -> ${OUT}`);