Весь арт первой игры генерируется кодом: tools/pixelart/*.mjs рисуют спрайты на собственном Canvas и кодируют PNG без сторонних зависимостей (node:zlib + свой CRC32). Позже генератор можно заменить на рисованный арт — движку всё равно, откуда текстуры.
| Файл | Что делает |
|---|---|
tools/pixelart/palette.mjs |
Палитра из 32 цветов (hex + RGBA) |
tools/pixelart/canvas.mjs |
Canvas: set/get пикселя, fillDiamond (изо-ромб), fromAscii, seeded rng |
tools/pixelart/png.mjs |
encodePng — сборка PNG вручную |
tools/pixelart/gen.mjs |
Генерация всех спрайтов игры → apps/game/assets/ |
npm run art # node tools/pixelart/gen.mjs — перегенерировать все PNG
Выходные файлы кладутся в apps/game/assets/ и грузятся в игре по ключам (tiles/grass, chars/hero_down_1, ...). Список ключей — в apps/game/src/Game.ts.
docs/art-style.md.Персонажи задаются ASCII-картами (символ → цвет палитры) — читается и правится прямо в коде:
const heroDown = fromAscii(`
....0000....
...011111...
...
`, { '0': 'P4', '1': 'F2' });
Тайлы земли рисуются шумом (seeded rng) + ромбы fillDiamond (свет — верхние склоны, тень — нижние). Дерево: «облачная» крона из перекрывающихся окружностей, ствол, свисающий кабель — детали сеттинга.
Если спрайтов много (анимации), генератор может собрать атлас: кадры в один PNG + Spritesheet JSON. Формат Pixi:
const atlas = {
frames: {
hero_walk_1: { frame: { x: 0, y: 0, w: 16, h: 24 } },
hero_walk_2: { frame: { x: 16, y: 0, w: 16, h: 24 } }
},
meta: { image: 'hero_sheet.png', size: { w: 32, h: 24 }, scale: 1 }
};
Загрузка в игре — assets.loadAtlas('chars/hero_sheet'), кадры — assets.frames(key, 'hero_walk').
Движку не важно происхождение текстур. Чтобы перейти на рисованный арт:
apps/game/assets/.docs/art-style.md).Aseprite/Piskel: экспорт в PNG с теми же именами файлов, что даёт генератор.