shots: render refuses missing frames and fails on load errors; shots check errors on renders with failed loads (pitfall 93)

This commit is contained in:
CRTkafa 2026-10-21 18:09:06 +07:00
parent 00756e6908
commit 88d1b58f1f
7 changed files with 78 additions and 2 deletions

View file

@ -25,7 +25,7 @@ import { done, log, warn } from '../lib/log';
import { closeBrowser, launch } from './browser';
import { defaultConcurrency, pool, progressLine } from './capture-web';
import { shotsStyle } from '../lib/config';
import { type CopyFile, type DeviceBox, type TextBox, SIZES, renderDims, sheetTimeoutMs, featureLayout, copyText, defaultSizes, frameDims, mergeCopy, palette, renderDir, scriptFont, sheetLayout, validateCopy, variantScenes } from './lib';
import { type CopyFile, type DeviceBox, type TextBox, SIZES, renderDims, sheetTimeoutMs, featureLayout, copyText, defaultSizes, frameDims, framesForRender, mergeCopy, palette, renderDir, scriptFont, sheetLayout, validateCopy, variantScenes } from './lib';
import { bgCss, bgTone, type ContrastSample, contrastIssues, parseColour, photoBackground, photoCss, type RGB, worstContrast } from './palette';
import { type WeightSample, weightIssues } from './weights';
import type { Palette } from '../lib/config';
@ -70,6 +70,12 @@ export async function run(ctx: Ctx): Promise<void> {
if (bad.length) throw new Error(`--scenes: unknown scene id${bad.length > 1 ? 's' : ''} ${bad.join(', ')}${v ? ` (variant ${v})` : ''}; scene ids: ${job.scenes.map(s => s.id).join(', ')}`);
}
const framesDir = resolve(shots.frames), outDir = resolve(shots.out);
// every frame the scenes load must exist: a missing one renders a store image with no app or game in it
const gone = [...jobs.values()].flatMap(job => {
const sel = a.list('scenes').length ? job.scenes.filter(s => a.list('scenes').includes(s.id)) : job.scenes;
return framesForRender(sel, sizes, langs, shots);
}).filter((f, i, all) => all.indexOf(f) === i && !existsSync(join(framesDir, f)));
if (gone.length) throw new Error(`shots render: ${gone.length} frame file${gone.length > 1 ? 's' : ''} missing under ${relative(root, framesDir) || '.'} (run \`storebound shots capture\` first, or restore the frames folder; it is often git-ignored):\n ${gone.slice(0, 20).join('\n ')}${gone.length > 20 ? `\n ... ${gone.length - 20} more` : ''}`);
if (a.has('dry')) {
let n = 0;
for (const [v, job] of jobs) for (const lang of langs) {
@ -290,6 +296,8 @@ export async function run(ctx: Ctx): Promise<void> {
server.stop(true);
if (Object.keys(report).length) writeFileSync(join(outDir, 'report.json'), JSON.stringify(mergeReport(readReport(outDir), report), null, 1) + '\n');
}
const broken = Object.entries(report).filter(([, r]) => r.missing?.length);
if (broken.length) throw new Error(`shots render: ${broken.length} image${broken.length > 1 ? 's' : ''} rendered with files that failed to load (frame, logo or background; the image has holes): ${broken.slice(0, 5).map(([k, r]) => `${k} (${r.missing!.join(', ')})`).join('; ')}${broken.length > 5 ? ' ...' : ''}`);
const flagged = Object.values(report).filter(r => r.overflow.length).length;
if (flagged) warn('shots', `${flagged} images with text overflow flags: storebound shots check / shots gallery`);
done('shots', `render done${warnings ? `, ${warnings} with warnings (missing frames or fonts?)` : ''}`);