mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-09-14 17:42:17 +00:00
perf(sprites): ship 192px sprites and a manifest of every sprite
Sprites were shipped at 512x512 but render at 44-64px in the box grid. Resizing to 192px halves each file (median 15.5KB -> 7.6KB); a full dex of artwork drops from 16.6MB to 7.6MB. The sprite build now also writes static/sprites-small/manifest.json, listing every sprite (all forms, shiny and female variants) with its size, so the offline worker can save the complete set and report what is missing. A unit test keeps it in step with the files on disk.
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env node
|
||||
// Lists every sprite (all forms, shiny and female variants) with its size, so the offline worker can
|
||||
// save the complete set on request and tell whether anything is still missing.
|
||||
import path from 'node:path';
|
||||
import process from 'node:process';
|
||||
import { readdir, stat, writeFile } from 'node:fs/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
export const SPRITE_MANIFEST_NAME = 'manifest.json';
|
||||
|
||||
async function walk(dir, files = []) {
|
||||
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) await walk(fullPath, files);
|
||||
else if (entry.isFile() && entry.name.endsWith('.webp')) files.push(fullPath);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/** Builds the manifest for `<spritesDir>/home`, with paths relative to that folder. */
|
||||
export async function buildSpriteManifest(spritesDir) {
|
||||
const homeDir = path.join(spritesDir, 'home');
|
||||
const files = await walk(homeDir);
|
||||
const entries = await Promise.all(
|
||||
files.map(async (file) => [
|
||||
path.relative(homeDir, file).split(path.sep).join('/'),
|
||||
(await stat(file)).size
|
||||
])
|
||||
);
|
||||
entries.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
||||
return { version: 1, files: entries };
|
||||
}
|
||||
|
||||
export async function writeSpriteManifest(spritesDir) {
|
||||
const manifest = await buildSpriteManifest(spritesDir);
|
||||
await writeFile(path.join(spritesDir, SPRITE_MANIFEST_NAME), `${JSON.stringify(manifest)}\n`);
|
||||
return manifest;
|
||||
}
|
||||
|
||||
if (process.argv[1] === fileURLToPath(import.meta.url)) {
|
||||
const spritesDir =
|
||||
process.env.SPRITE_OUTPUT_DIR ?? path.join(process.cwd(), 'static', 'sprites-small');
|
||||
const manifest = await writeSpriteManifest(spritesDir);
|
||||
const bytes = manifest.files.reduce((total, [, size]) => total + size, 0);
|
||||
console.log(
|
||||
`Wrote ${manifest.files.length} sprites (${(bytes / 1048576).toFixed(1)} MB) to ${SPRITE_MANIFEST_NAME}`
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user