shots: full-bleed layout (shots.layout bleed) with corner captions, per-size frames, and landscape orientation, on top of the landscape sizes

This commit is contained in:
CRTkafa 2026-10-23 22:45:10 +08:00
parent 9ed1890de8
commit d4cf1ad3a1
11 changed files with 320 additions and 11 deletions

View file

@ -32,11 +32,13 @@ export const PLAY_TABLET_LANDSCAPE: Record<string, { w: number; h: number }> = {
/** Pixel size and layout of one size key for a project: the landscape layout for mac / chromebook, and for the Play
* tablet slots with shots.landscape.playTablets. frame = the device drawn around a landscape frame ('window' = a Mac
* window, 'none' = the bare frame with rounded corners); default window on Mac, none on Play. Pure. */
export function renderDims(size: string, shots: Pick<ShotsConfig, 'landscape'> | undefined): { w: number; h: number; landscape: boolean; frame: 'window' | 'none' } {
export function renderDims(size: string, shots: Pick<ShotsConfig, 'landscape' | 'orientation'> | undefined): { w: number; h: number; landscape: boolean; frame: 'window' | 'none' } {
const s = SIZES[size]!;
const tabLand = !!shots?.landscape?.playTablets && !!PLAY_TABLET_LANDSCAPE[size];
const landscape = s.device === 'landscape' || tabLand;
const d = tabLand ? PLAY_TABLET_LANDSCAPE[size]! : s;
// shots.orientation 'landscape' (bleed layout): every other portrait screenshot size swaps width and height
const swap = shots?.orientation === 'landscape' && !s.feature && !landscape;
const d = tabLand ? PLAY_TABLET_LANDSCAPE[size]! : swap ? { w: s.h, h: s.w } : s;
const frame = shots?.landscape?.frame ?? (size === 'mac' ? 'window' : 'none');
return { w: d.w, h: d.h, landscape, frame };
}
@ -310,11 +312,16 @@ export function boxOutside(b: DeviceBox, W: number, H: number, tol = 1): string[
* loads. A missing one renders an image with no app or game content (only a 404 in the page), so `shots render`
* refuses to start without them. Landscape layouts use each scene's first frame; the feature graphic a phone frame. */
export function framesForRender(scenes: { frames: { src: string }[] }[], sizes: string[], langs: string[],
shots: Pick<ShotsConfig, 'landscape'> & { feature?: { frame?: string } }): string[] {
shots: Pick<ShotsConfig, 'landscape' | 'layout'> & { feature?: { frame?: string } }): string[] {
const out = new Set<string>();
for (const lang of langs) for (const size of sizes) {
const s = SIZES[size];
if (!s) continue;
if (shots.layout === 'bleed') { // one frame per scene at each size's own pixels: <lang>/<size>/<src>, the feature one in <lang>/feature/
if (s.feature) { const f = shots.feature?.frame ?? scenes[0]?.frames[0]?.src; if (f) out.add(`${lang}/feature/${f}`); }
else for (const sc of scenes) if (sc.frames[0]) out.add(`${lang}/${size}/${sc.frames[0].src}`);
continue;
}
if (s.feature) { const f = shots.feature?.frame ?? scenes[0]?.frames[0]?.src; if (f) out.add(`${lang}/phone/${f}`); continue; }
const d = renderDims(size, shots);
const kind = d.landscape ? 'landscape' : s.device ? 'tablet' : 'phone';