shots: app titles get the weights the templates use (variable axis, used range or static weights; font-weight warning), palette.bg as one colour or a CSS gradient string (validated; contrast guard in shots check), photo backgrounds (palette.image, shots.feature.background) with overlay and cover crop
This commit is contained in:
parent
2ba8278ab7
commit
3a11682a37
21 changed files with 713 additions and 44 deletions
|
|
@ -21,6 +21,39 @@ import { allIssues, requiredSets, type RendersScan, resolvedTablets, scanRenders
|
|||
import { imageInfo } from './spec';
|
||||
import { fontsDirOf, readManifest } from './fonts';
|
||||
import { localFontIssues } from './local-fonts';
|
||||
import { photoBackground, photoIssues } from './palette';
|
||||
import { palette } from './lib';
|
||||
import { shotsStyle } from '../lib/config';
|
||||
import type { Issue } from './spec';
|
||||
|
||||
/** Photo backgrounds (palette.image, shots.feature.background): the file exists and is at least as big as every
|
||||
* output it covers (the feature graphic 1024 x 500; screenshots at the sizes this project renders). */
|
||||
export function backgroundIssues(config: ShipConfig, resolve: (p: string) => string, tablets?: boolean): { where: string; issue: Issue }[] {
|
||||
const shots = config.shots;
|
||||
if (!shots) return [];
|
||||
const style = shotsStyle(config), sizes = defaultSizes(config, tablets);
|
||||
const out: { where: string; issue: Issue }[] = [];
|
||||
const one = (file: string, where: string, targets: string[]): void => {
|
||||
const abs = resolve(file);
|
||||
let info: { w: number; h: number } | null = null;
|
||||
try { const i = imageInfo(readFileSync(abs)); info = i.format === 'unknown' ? null : i; } catch { /* missing */ }
|
||||
for (const t of targets) for (const x of photoIssues(info, file, SIZES[t]!.w, SIZES[t]!.h)) out.push({ where, issue: { level: x.level, code: 'background', msg: x.msg } });
|
||||
};
|
||||
const screens = sizes.filter(s => !SIZES[s]!.feature);
|
||||
// the biggest screenshot size decides; one message per file
|
||||
const biggest = screens.sort((a, b) => SIZES[b]!.w * SIZES[b]!.h - SIZES[a]!.w * SIZES[a]!.h).slice(0, 1);
|
||||
for (const sc of shots.scenes) {
|
||||
let p; try { p = palette(sc.palette, style); } catch (e) { out.push({ where: `shots.scenes[${sc.id}].palette`, issue: { level: 'error', code: 'background', msg: (e as Error).message } }); continue; }
|
||||
const ph = photoBackground(p);
|
||||
if (ph) one(ph.image, `shots.scenes[${sc.id}].palette.image`, biggest);
|
||||
}
|
||||
if (sizes.includes('feature')) {
|
||||
let p; try { p = palette(shots.feature?.palette ?? shots.scenes[0]?.palette, style); } catch { p = null; }
|
||||
const ph = p && photoBackground(p, shots.feature?.background);
|
||||
if (ph) one(ph.image, shots.feature?.background ? 'shots.feature.background' : 'shots.feature palette.image', ['feature']);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Frame files the scenes (and the feature graphic) use, per language and device class. */
|
||||
export function framesNeeded(config: ShipConfig, langs: string[], tablets?: boolean): { lang: string; device: 'phone' | 'tablet'; name: string }[] {
|
||||
|
|
@ -66,9 +99,10 @@ export function rendersCheck(config: ShipConfig, dir: string): Record<'apple' |
|
|||
export async function run(ctx: Ctx): Promise<void> {
|
||||
const { config, resolve, root } = ctx.loaded;
|
||||
const scan = scanProject(ctx);
|
||||
const issues = [...allIssues(scan), ...localFontIssues(readManifest(fontsDirOf(root))).map(issue => ({ where: '.storebound/fonts/fonts.json', issue }))];
|
||||
const cap = config.shots?.capture;
|
||||
const tablets = resolvedTablets(config, resolve(ctx.args.get('src') ?? config.renders ?? config.shots?.out ?? 'store/renders'));
|
||||
const issues = [...allIssues(scan), ...localFontIssues(readManifest(fontsDirOf(root))).map(issue => ({ where: '.storebound/fonts/fonts.json', issue })),
|
||||
...backgroundIssues(config, resolve, tablets)];
|
||||
const frameIssues = cap?.source === 'folder' ? checkFrameFolder(config, resolve(cap.folder ?? config.shots!.frames), scan.langs, tablets) : [];
|
||||
if (ctx.args.has('json')) {
|
||||
printJson({ images: scan.images.length, videos: scan.videos.length, issues, frames: frameIssues });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue